* [PATCH 0/4 v3] Add support for static and SystemTap probes
@ 2012-04-23 4:57 Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 1/4 v3] Refactor internal variable mechanism Sergio Durigan Junior
` (4 more replies)
0 siblings, 5 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-23 4:57 UTC (permalink / raw)
To: gdb-patches
Hello,
After long days reviewing Jan's request about more abstraction, I think
I am now ready for the third submission of the SystemTap + static probes
patch. Note that now I decided to claim that this patch series is
actually adding support not only for SystemTap, but also adding a
frontend which can theorically support any kind of static probe.
Again, the full explanation for these patches are in:
http://sourceware.org/ml/gdb-patches/2012-03/msg00353.html
With the difference that the new commands are `-probe' (for generic
probes), `-pstap' and `-probe-stap' (for SystemTap specific probes).
Note also that if you use `-probe' with a SystemTap probe, GDB will
automagically use the SystemTap backend for it.
I really cannot remember anything more to say about this. Again, if you
want to narrow your review, patch #2 should be the most interesting.
The doc bits have already been aproved in the last attempt, and they
were not modified since then, but I'm sending them either way.
Regtested on Fedora x86_64, no regressions. Comments are welcome.
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 2/4 v3] Implement support for static and SystemTap probes
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 1/4 v3] Refactor internal variable mechanism Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 3/4 v3] Use longjmp and exception probes when available Sergio Durigan Junior
@ 2012-04-23 4:59 ` Sergio Durigan Junior
2012-04-27 19:43 ` Tom Tromey
2012-04-23 6:35 ` [PATCH 4/4 v3] Documentation and testsuite changes Sergio Durigan Junior
2012-04-28 23:30 ` Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes] Jan Kratochvil
4 siblings, 1 reply; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-23 4:59 UTC (permalink / raw)
To: gdb-patches
Hi,
This is the largest patch. It contains the fully abstracted API for
creating static probes, and also the code for SystemTap probe.
OK to check-in?
Thanks.
2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* Makefile.in (SFILES): Add `probe' and `stap-probe'.
(COMMON_OBS): Likewise.
(HFILES_NO_SRCDIR): Add `probe'.
* NEWS: Mention support for static and SystemTap probes.
* amd64-tdep.c (amd64_init_abi): Initializing proper fields used by
SystemTap probes' arguments parser.
* arm-linux-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(arm_stap_is_single_operand): New function.
(arm_stap_parse_special_token): Likewise.
(arm_linux_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* ax-gdb.c (require_rvalue): Removing static declaration.
(gen_expr): Likewise.
* ax-gdb.h (gen_expr): Declaring function.
(require_rvalue): Likewise.
* breakpoint.c: Include `gdb_regex.h' and `probe.h'.
(bkpt_probe_breakpoint_ops): New variable.
(momentary_breakpoint_from_master): Set the `probe' value.
(add_location_to_breakpoint): Likewise.
(break_command_1): Using proper breakpoint_ops according to the
argument passed by the user in the command line.
(bkpt_probe_insert_location): New function.
(bkpt_probe_remove_location): Likewise.
(bkpt_probe_create_sals_from_address): Likewise.
(bkpt_probe_decode_linespec): Likewise.
(tracepoint_probe_create_sals_from_address): Likewise.
(tracepoint_probe_decode_linespec): Likewise.
(tracepoint_probe_breakpoint_ops): New variable.
(trace_command): Using proper breakpoint_ops according to the
argument passed by the user in the command line.
(initialize_breakpoint_ops): Initializing breakpoint_ops for
static probes on breakpoints and tracepoints.
* breakpoint.h (struct bp_location) <probe>: New field.
* cli-utils.c (skip_spaces_const): New function.
(extract_arg): Likewise.
* cli-utils.h (skip_spaces_const): Likewise.
(extract_arg): Likewise.
* coffread.c (coff_sym_fns): Add `sym_probe_fns' value.
* configure.ac: Append `stap-probe.o' to be generated when ELF
support is present.
* configure: Regenerate.
* dbxread.c (aout_sym_fns): Add `sym_probe_fns' value.
* elfread.c: Include `probe.h' and `arch-utils.h'.
(probe_key): New variable.
(elf_get_probes): New function.
(elf_get_probe_argument_count): Likewise.
(elf_evaluate_probe_argument): Likewise.
(elf_compile_to_ax): Likewise.
(elf_symfile_relocate_probe): Likewise.
(stap_probe_key_free): Likewise.
(elf_probe_fns): New variable.
(elf_sym_fns): Add `sym_probe_fns' value.
(elf_sym_fns_lazy_psyms): Likewise.
(elf_sym_fns_gdb_index): Likewise.
(_initialize_elfread): Initialize objfile cache for static
probes.
* gdb_vecs.h (struct probe): New forward declaration.
(probe_p): New VEC declaration.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh (stap_integer_prefix): New variable.
(stap_integer_suffix): Likewise.
(stap_register_prefix): Likewise.
(stap_register_suffix): Likewise.
(stap_register_indirection_prefix): Likewise.
(stap_register_indirection_suffix): Likewise.
(stap_gdb_register_prefix): Likewise.
(stap_gdb_register_suffix): Likewise.
(stap_is_single_operand): New function.
(stap_parse_special_token): Likewise.
(struct stap_parse_info): Forward declaration.
* i386-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(i386_stap_is_single_operand): New function.
(i386_stap_parse_special_token): Likewise.
(i386_elf_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* i386-tdep.h (i386_stap_is_single_operand): New function.
(i386_stap_parse_special_token): Likewise.
* machoread.c (macho_sym_fns): Add `sym_probe_fns' value.
* mipsread.c (ecoff_sym_fns): Likewise.
* objfiles.c (objfile_relocate1): Support relocation for static
probes.
* parse.c (prefixify_expression): Remove static declaration.
(initialize_expout): Likewise.
(reallocate_expout): Likewise.
* parser-defs.h (initialize_expout): Declare function.
(reallocate_expout): Likewise.
(prefixify_expression): Likewise.
* ppc-linux-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(ppc_stap_is_single_operand): New function.
(ppc_stap_parse_special_token): Likewise.
(ppc_linux_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* probe.c: New file, for generic statically defined probe support.
* probe.h: Likewise.
* s390-tdep.c: Including headers needed to perform the parsing of
SystemTap probes' arguments.
(s390_stap_is_single_operand): New function.
(s390_gdbarch_init): Initializing proper fields used by SystemTap
probes' arguments parser.
* somread.c (som_sym_fns): Add `sym_probe_fns' value.
* stap-probe.c: New file, for SystemTap probe support.
* stap-probe.h: Likewise.
* symfile.h: Include `gdb_vecs.h'.
(struct sym_probe_fns): New struct.
(struct sym_fns) <sym_probe_fns>: New field.
* symtab.c (init_sal): Initialize `probe' field.
* symtab.h (struct probe): Forward declaration.
(struct symtab_and_line) <probe>: New field.
* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
locations.
(stop_tracing): Likewise.
* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
---
gdb/Makefile.in | 8 +-
gdb/NEWS | 7 +
gdb/amd64-tdep.c | 10 +
gdb/arm-linux-tdep.c | 132 +++++
gdb/ax-gdb.c | 8 +-
gdb/ax-gdb.h | 5 +
gdb/breakpoint.c | 119 ++++-
gdb/breakpoint.h | 4 +
gdb/cli/cli-utils.c | 41 ++
gdb/cli/cli-utils.h | 11 +
gdb/coffread.c | 1 +
gdb/configure | 2 +-
gdb/configure.ac | 2 +-
gdb/dbxread.c | 1 +
gdb/elfread.c | 120 ++++
gdb/gdb_vecs.h | 5 +
gdb/gdbarch.c | 250 ++++++++
gdb/gdbarch.h | 120 ++++
gdb/gdbarch.sh | 96 +++
gdb/i386-tdep.c | 336 +++++++++++
gdb/i386-tdep.h | 9 +
gdb/machoread.c | 1 +
gdb/mipsread.c | 1 +
gdb/objfiles.c | 5 +
gdb/parse.c | 26 +-
gdb/parser-defs.h | 24 +
gdb/ppc-linux-tdep.c | 86 +++
gdb/probe.c | 788 +++++++++++++++++++++++++
gdb/probe.h | 221 +++++++
gdb/s390-tdep.c | 26 +-
gdb/somread.c | 1 +
gdb/stap-probe.c | 1558 ++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/stap-probe.h | 52 ++
gdb/symfile.h | 56 ++
gdb/symtab.c | 1 +
gdb/symtab.h | 4 +
gdb/tracepoint.c | 30 +
gdb/xcoffread.c | 1 +
38 files changed, 4133 insertions(+), 35 deletions(-)
create mode 100644 gdb/probe.c
create mode 100644 gdb/probe.h
create mode 100644 gdb/stap-probe.c
create mode 100644 gdb/stap-probe.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0e87eeb..df6a0f8 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -725,8 +725,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
sentinel-frame.c \
serial.c ser-base.c ser-unix.c skip.c \
solib.c solib-target.c source.c \
- stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
- symtab.c \
+ stabsread.c stack.c probe.c stap-probe.c std-regs.c \
+ symfile.c symfile-mem.c symmisc.c symtab.c \
target.c target-descriptions.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
@@ -825,7 +825,7 @@ gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h
gnulib/import/extra/snippet/warn-on-use.h \
gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/linux-osdata.h gdb-dlfcn.h auto-load.h
+common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -912,7 +912,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
xml-support.o xml-syscall.o xml-utils.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
- jit.o progspace.o skip.o \
+ jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o
TSOBS = inflow.o
diff --git a/gdb/NEWS b/gdb/NEWS
index 72b4d90..a19424a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
*** Changes since GDB 7.4
+* GDB now has support for SDT (Static Defined Tracing) probes. Currently,
+ the only implemented backend is for SystemTap probes (<sys/sdt.h>). You
+ can set a breakpoint using the new "-probe, "-pstap" or "-probe-stap"
+ options and inspect the probe arguments using the new $_probe_arg family
+ of convenience variables. You can obtain more information about SystemTap
+ in <http://sourceware.org/systemtap/>.
+
* GDB now supports reversible debugging on ARM, it allows you to
debug basic ARM and THUMB instructions, and provides
record/replay support.
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index d15acea..685fa48 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -2691,6 +2691,16 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address);
+
+ /* SystemTap variables and functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "$");
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch,
+ i386_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ i386_stap_parse_special_token);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 486e6ed..f4eaa5c 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -43,6 +43,12 @@
#include "gdbthread.h"
#include "symfile.h"
+#include "cli/cli-utils.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
#include "gdb_string.h"
/* This is defined in <elf.h> on ARM GNU/Linux systems. */
@@ -1056,6 +1062,122 @@ arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
return dsc;
}
+static int
+arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == '#' /* Literal number. */
+ || *s == '[' /* Register indirection or
+ displacement. */
+ || isalpha (*s)); /* Register value. */
+}
+
+/* This routine is used to parse a special token in ARM's assembly.
+
+ The special tokens parsed by it are:
+
+ - Register displacement (e.g, [fp, #-8])
+
+ It returns one if the special token has been parsed successfully,
+ or zero if the current token is not considered special. */
+
+static int
+arm_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ if (*p->arg == '[')
+ {
+ /* Temporary holder for lookahead. */
+ const char *tmp = p->arg;
+ /* Used to save the register name. */
+ const char *start;
+ char *regname;
+ int len, offset;
+ int got_minus = 0;
+ long displacement;
+ struct stoken str;
+
+ ++tmp;
+ start = tmp;
+
+ /* Register name. */
+ while (isalnum (*tmp))
+ ++tmp;
+
+ if (*tmp != ',')
+ return 0;
+
+ len = tmp - start;
+ regname = alloca (len + 2);
+
+ offset = 0;
+ if (isdigit (*start))
+ {
+ /* If we are dealing with a register whose name begins with a
+ digit, it means we should prefix the name with the letter
+ `r', because GDB expects this name pattern. Otherwise (e.g.,
+ we are dealing with the register `fp'), we don't need to
+ add such a prefix. */
+ regname[0] = 'r';
+ offset = 1;
+ }
+
+ strncpy (regname + offset, start, len);
+ len += offset;
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ ++tmp;
+ tmp = skip_spaces_const (tmp);
+ if (*tmp++ != '#')
+ return 0;
+
+ if (*tmp == '-')
+ {
+ ++tmp;
+ got_minus = 1;
+ }
+
+ displacement = strtol (tmp, (char **) &tmp, 10);
+
+ /* Skipping last `]'. */
+ if (*tmp++ != ']')
+ return 0;
+
+ /* The displacement. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacement);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+
+ /* The register name. */
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ write_exp_elt_opcode (BINOP_ADD);
+
+ /* Casting to the expected type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = tmp;
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -1158,6 +1280,16 @@ arm_linux_init_abi (struct gdbarch_info info,
/* Reversible debugging, process record. */
set_gdbarch_process_record (gdbarch, arm_process_record);
+ /* SystemTap functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "#");
+ set_gdbarch_stap_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "[");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, "]");
+ set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_is_single_operand (gdbarch, arm_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ arm_stap_parse_special_token);
+
tdep->syscall_next_pc = arm_linux_syscall_next_pc;
/* Syscall record. */
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index eebe61a..909f282 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -95,8 +95,6 @@ static void gen_int_literal (struct agent_expr *ax,
struct axs_value *value,
LONGEST k, struct type *type);
-
-static void require_rvalue (struct agent_expr *ax, struct axs_value *value);
static void gen_usual_unary (struct expression *exp, struct agent_expr *ax,
struct axs_value *value);
static int type_wider_than (struct type *type1, struct type *type2);
@@ -157,8 +155,6 @@ static void gen_repeat (struct expression *exp, union exp_element **pc,
static void gen_sizeof (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value,
struct type *size_type);
-static void gen_expr (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
static void gen_expr_binop_rest (struct expression *exp,
enum exp_opcode op, union exp_element **pc,
struct agent_expr *ax,
@@ -791,7 +787,7 @@ gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k,
/* Take what's on the top of the stack (as described by VALUE), and
try to make an rvalue out of it. Signal an error if we can't do
that. */
-static void
+void
require_rvalue (struct agent_expr *ax, struct axs_value *value)
{
/* Only deal with scalars, structs and such may be too large
@@ -1803,7 +1799,7 @@ gen_sizeof (struct expression *exp, union exp_element **pc,
/* XXX: i18n */
/* A gen_expr function written by a Gen-X'er guy.
Append code for the subexpression of EXPR starting at *POS_P to AX. */
-static void
+void
gen_expr (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value)
{
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index 48c35a4..09f6889 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -110,6 +110,11 @@ extern struct agent_expr *gen_trace_for_return_address (CORE_ADDR,
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
+extern void gen_expr (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value);
+
+extern void require_rvalue (struct agent_expr *ax, struct axs_value *value);
+
extern int trace_kludge;
extern int trace_string_kludge;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index be536bc..ce0ee62 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -60,6 +60,8 @@
#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "gdb_regex.h"
+#include "probe.h"
#include "cli/cli-utils.h"
#include "continuations.h"
#include "stack.h"
@@ -290,6 +292,9 @@ static struct breakpoint_ops momentary_breakpoint_ops;
breakpoints. */
struct breakpoint_ops bkpt_breakpoint_ops;
+/* Breakpoints set on probes. */
+static struct breakpoint_ops bkpt_probe_breakpoint_ops;
+
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
struct counted_command_line
@@ -8138,6 +8143,7 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
+ copy->loc->probe = orig->loc->probe;
if (orig->loc->source_file != NULL)
copy->loc->source_file = xstrdup (orig->loc->source_file);
@@ -8223,6 +8229,7 @@ add_location_to_breakpoint (struct breakpoint *b,
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
+ loc->probe = sal->probe;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
@@ -8962,6 +8969,14 @@ break_command_1 (char *arg, int flag, int from_tty)
enum bptype type_wanted = (flag & BP_HARDWAREFLAG
? bp_hardware_breakpoint
: bp_breakpoint);
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ /* Matching breakpoints on probes. */
+ if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
+ ops = &bkpt_probe_breakpoint_ops;
+ else
+ ops = &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (),
arg,
@@ -8969,7 +8984,7 @@ break_command_1 (char *arg, int flag, int from_tty)
tempflag, type_wanted,
0 /* Ignore count */,
pending_break_support,
- &bkpt_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
0 /* internal */,
@@ -12443,6 +12458,57 @@ momentary_bkpt_print_mention (struct breakpoint *b)
/* Nothing to mention. These breakpoints are internal. */
}
+/* Specific methods for probe breakpoints. */
+
+static int
+bkpt_probe_insert_location (struct bp_location *bl)
+{
+ int v = bkpt_insert_location (bl);
+
+ if (v == 0)
+ {
+ /* The insertion was successful, now let's set the probe's semaphore
+ if needed. */
+ bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
+ }
+
+ return v;
+}
+
+static int
+bkpt_probe_remove_location (struct bp_location *bl)
+{
+ /* Let's clear the semaphore before removing the location. */
+ bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
+
+ return bkpt_remove_location (bl);
+}
+
+static void
+bkpt_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ struct linespec_sals lsal;
+
+ lsal.sals = parse_probes (arg, canonical);
+
+ *copy_arg = xstrdup (canonical->addr_string);
+ lsal.canonical = xstrdup (*copy_arg);
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ *sals = parse_probes (s, NULL);
+ if (!sals->sals)
+ error (_("probe not found"));
+}
+
/* The breakpoint_ops structure to be used in tracepoints. */
static void
@@ -12566,6 +12632,30 @@ tracepoint_decode_linespec (struct breakpoint *b, char **s,
struct breakpoint_ops tracepoint_breakpoint_ops;
+/* The breakpoint_ops structure to be use on tracepoints placed in a
+ static probe. */
+
+static void
+tracepoint_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
+ addr_start, copy_arg);
+}
+
+static void
+tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ /* We use the same method for breakpoint on probes. */
+ bkpt_probe_decode_linespec (b, s, sals);
+}
+
+static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
+
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
@@ -14197,6 +14287,14 @@ set_tracepoint_count (int num)
static void
trace_command (char *arg, int from_tty)
{
+ struct breakpoint_ops *ops;
+ const char *arg_cp = arg;
+
+ if (arg && probe_linespec_to_ops (&arg_cp))
+ ops = &tracepoint_probe_breakpoint_ops;
+ else
+ ops = &tracepoint_breakpoint_ops;
+
if (create_breakpoint (get_current_arch (),
arg,
NULL, 0, 1 /* parse arg */,
@@ -14204,7 +14302,7 @@ trace_command (char *arg, int from_tty)
bp_tracepoint /* type_wanted */,
0 /* Ignore count */,
pending_break_support,
- &tracepoint_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
0 /* internal */, 0))
@@ -14939,6 +15037,14 @@ initialize_breakpoint_ops (void)
ops->print_it = momentary_bkpt_print_it;
ops->print_mention = momentary_bkpt_print_mention;
+ /* Probe breakpoints. */
+ ops = &bkpt_probe_breakpoint_ops;
+ *ops = bkpt_breakpoint_ops;
+ ops->insert_location = bkpt_probe_insert_location;
+ ops->remove_location = bkpt_probe_remove_location;
+ ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
+ ops->decode_linespec = bkpt_probe_decode_linespec;
+
/* GNU v3 exception catchpoints. */
ops = &gnu_v3_exception_catchpoint_ops;
*ops = bkpt_breakpoint_ops;
@@ -14986,6 +15092,12 @@ initialize_breakpoint_ops (void)
ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
ops->decode_linespec = tracepoint_decode_linespec;
+ /* Probe tracepoints. */
+ ops = &tracepoint_probe_breakpoint_ops;
+ *ops = tracepoint_breakpoint_ops;
+ ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
+ ops->decode_linespec = tracepoint_probe_decode_linespec;
+
/* Static tracepoints with marker (`-m'). */
ops = &strace_marker_breakpoint_ops;
*ops = tracepoint_breakpoint_ops;
@@ -15064,7 +15176,8 @@ _initialize_breakpoint (void)
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
- breakpoint_objfile_key = register_objfile_data ();
+ breakpoint_objfile_key
+ = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
catch_syscall_inferior_data
= register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e0eeeaa..b22eb66 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -418,6 +418,10 @@ struct bp_location
processor's architectual constraints. */
CORE_ADDR requested_address;
+ /* If the location comes from a probe point, this is the probe associated
+ with it. */
+ struct probe *probe;
+
char *function_name;
/* Details of the placed breakpoint, when inserted. */
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index a7b2718..3239a46 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -223,6 +223,18 @@ skip_spaces (char *chp)
return chp;
}
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
/* See documentation in cli-utils.h. */
char *
@@ -245,3 +257,32 @@ remove_trailing_whitespace (const char *start, char *s)
return s;
}
+
+/* See documentation in cli-utils.h. */
+
+char *
+extract_arg (char **arg)
+{
+ char *result, *copy;
+
+ if (!*arg)
+ return NULL;
+
+ /* Find the start of the argument. */
+ *arg = skip_spaces (*arg);
+ if (!**arg)
+ return NULL;
+ result = *arg;
+
+ /* Find the end of the argument. */
+ *arg = skip_to_space (*arg + 1);
+
+ if (result == *arg)
+ return NULL;
+
+ copy = xmalloc (*arg - result + 1);
+ memcpy (copy, result, *arg - result);
+ copy[*arg - result] = '\0';
+
+ return copy;
+}
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index e23c7d8..5f8a91d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -94,6 +94,10 @@ extern int number_is_in_list (char *list, int number);
extern char *skip_spaces (char *inp);
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
@@ -103,4 +107,11 @@ extern char *skip_to_space (char *inp);
START. */
extern char *remove_trailing_whitespace (const char *start, char *s);
+
+/* A helper function to extract an argument from *ARG. An argument is
+ delimited by whitespace. The return value is either NULL if no
+ argument was found, or an xmalloc'd string. */
+
+extern char *extract_arg (char **arg);
+
#endif /* CLI_UTILS_H */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 7c59535..2a8ee42 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2196,6 +2196,7 @@ static const struct sym_fns coff_sym_fns =
default_symfile_relocate, /* sym_relocate: Relocate a debug
section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/configure b/gdb/configure
index 54c2399..7370309 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -12447,7 +12447,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_var_elf" >&5
$as_echo "$gdb_cv_var_elf" >&6; }
if test $gdb_cv_var_elf = yes; then
- CONFIG_OBS="$CONFIG_OBS elfread.o"
+ CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
$as_echo "#define HAVE_ELF 1" >>confdefs.h
diff --git a/gdb/configure.ac b/gdb/configure.ac
index a40c2e5..9089f4d 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1947,7 +1947,7 @@ AC_CACHE_CHECK([for ELF support in BFD], gdb_cv_var_elf,
[bfd *abfd = NULL; bfd_get_elf_phdr_upper_bound (abfd); ],
gdb_cv_var_elf=yes, gdb_cv_var_elf=no)])
if test $gdb_cv_var_elf = yes; then
- CONFIG_OBS="$CONFIG_OBS elfread.o"
+ CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
AC_DEFINE(HAVE_ELF, 1,
[Define if ELF support should be included.])
# -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 1725112..2d47407 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -3589,6 +3589,7 @@ static const struct sym_fns aout_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 117e674..d825d9a 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -36,6 +36,8 @@
#include "demangle.h"
#include "psympriv.h"
#include "filenames.h"
+#include "probe.h"
+#include "arch-utils.h"
#include "gdbtypes.h"
#include "value.h"
#include "infcall.h"
@@ -60,6 +62,10 @@ struct elfinfo
asection *mdebugsect; /* Section pointer for .mdebug section */
};
+/* Per-objfile data for probe info. */
+
+static const struct objfile_data *probe_key = NULL;
+
static void free_elfinfo (void *);
/* Minimal symbols located at the GOT entries for .plt - that is the real
@@ -1576,7 +1582,117 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
complaint (&symfile_complaints,
_("elf/stab section information missing for %s"), filename);
}
+
+/* Implementation of `sym_get_probes', as documented in symfile.h. */
+
+static VEC (probe_p) *
+elf_get_probes (struct objfile *objfile)
+{
+ VEC (probe_p) *probes_per_objfile;
+
+ /* Have we parsed this objfile's probes already? */
+ probes_per_objfile = objfile_data (objfile, probe_key);
+
+ if (!probes_per_objfile)
+ {
+ int ix;
+ const struct probe_ops *probe_ops;
+
+ /* Here we try to gather information about all types of probes from the
+ objfile. */
+ for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops);
+ ix++)
+ probe_ops->get_probes (&probes_per_objfile, objfile);
+
+ if (probes_per_objfile == NULL)
+ {
+ VEC_reserve (probe_p, probes_per_objfile, 1);
+ gdb_assert (probes_per_objfile != NULL);
+ }
+
+ set_objfile_data (objfile, probe_key, probes_per_objfile);
+ }
+
+ return probes_per_objfile;
+}
+
+/* Implementation of `sym_get_probe_argument_count', as documented in
+ symfile.h. */
+
+static unsigned
+elf_get_probe_argument_count (struct objfile *objfile,
+ struct probe *probe)
+{
+ return probe->pops->get_probe_argument_count (probe, objfile);
+}
+
+/* Implementation of `sym_evaluate_probe_argument', as documented in
+ symfile.h. */
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+ struct probe *probe,
+ unsigned n)
+{
+ return probe->pops->evaluate_probe_argument (probe, objfile, n);
+}
+
+/* Implementation of `sym_compile_to_ax', as documented in symfile.h. */
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+ struct probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ unsigned n)
+{
+ probe->pops->compile_to_ax (probe, objfile, expr, value, n);
+}
+
+/* Implementation of `sym_relocate_probe', as documented in symfile.h. */
+
+static void
+elf_symfile_relocate_probe (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta)
+{
+ int ix;
+ VEC (probe_p) *probes = objfile_data (objfile, probe_key);
+ struct probe *probe;
+
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ probe->pops->relocate (probe, ANOFFSET (delta, SECT_OFF_TEXT (objfile)));
+}
+
+/* Helper function used to free the space allocated for storing SystemTap
+ probe information. */
+
+static void
+probe_key_free (struct objfile *objfile, void *d)
+{
+ int ix;
+ VEC (probe_p) *probes = d;
+ struct probe *probe;
+
+ for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
+ probe->pops->destroy (probe);
+
+ VEC_free (probe_p, probes);
+}
+
\f
+
+/* Implementation `sym_probe_fns', as documented in symfile.h. */
+
+static const struct sym_probe_fns elf_probe_fns =
+{
+ elf_get_probes, /* sym_get_probes */
+ elf_get_probe_argument_count, /* sym_get_probe_argument_count */
+ elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */
+ elf_compile_to_ax, /* sym_compile_to_ax */
+ elf_symfile_relocate_probe, /* sym_relocate_probe */
+};
+
/* Register that we are able to handle ELF object file formats. */
static const struct sym_fns elf_sym_fns =
@@ -1591,6 +1707,7 @@ static const struct sym_fns elf_sym_fns =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1609,6 +1726,7 @@ static const struct sym_fns elf_sym_fns_lazy_psyms =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1626,6 +1744,7 @@ static const struct sym_fns elf_sym_fns_gdb_index =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&dwarf2_gdb_index_functions
};
@@ -1642,6 +1761,7 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
void
_initialize_elfread (void)
{
+ probe_key = register_objfile_data_with_cleanup (NULL, probe_key_free);
add_symtab_fns (&elf_sym_fns);
elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
diff --git a/gdb/gdb_vecs.h b/gdb/gdb_vecs.h
index ce32de3..d6de54a 100644
--- a/gdb/gdb_vecs.h
+++ b/gdb/gdb_vecs.h
@@ -23,6 +23,8 @@
#include "vec.h"
+struct probe;
+
DEF_VEC_P (char_ptr);
DEF_VEC_P (const_char_ptr);
@@ -39,4 +41,7 @@ extern void dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp,
extern VEC (char_ptr) *dirnames_to_char_ptr_vec (const char *dirnames);
+typedef struct probe *probe_p;
+DEF_VEC_P (probe_p);
+
#endif /* GDB_VECS_H */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c079932..056dd5a 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -265,6 +265,16 @@ struct gdbarch
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
gdbarch_record_special_symbol_ftype *record_special_symbol;
gdbarch_get_syscall_number_ftype *get_syscall_number;
+ const char * stap_integer_prefix;
+ const char * stap_integer_suffix;
+ const char * stap_register_prefix;
+ const char * stap_register_suffix;
+ const char * stap_register_indirection_prefix;
+ const char * stap_register_indirection_suffix;
+ const char * stap_gdb_register_prefix;
+ const char * stap_gdb_register_suffix;
+ gdbarch_stap_is_single_operand_ftype *stap_is_single_operand;
+ gdbarch_stap_parse_special_token_ftype *stap_parse_special_token;
int has_global_solist;
int has_global_breakpoints;
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
@@ -423,6 +433,16 @@ struct gdbarch startup_gdbarch =
0, /* get_siginfo_type */
0, /* record_special_symbol */
0, /* get_syscall_number */
+ 0, /* stap_integer_prefix */
+ 0, /* stap_integer_suffix */
+ 0, /* stap_register_prefix */
+ 0, /* stap_register_suffix */
+ 0, /* stap_register_indirection_prefix */
+ 0, /* stap_register_indirection_suffix */
+ 0, /* stap_gdb_register_prefix */
+ 0, /* stap_gdb_register_suffix */
+ 0, /* stap_is_single_operand */
+ 0, /* stap_parse_special_token */
0, /* has_global_solist */
0, /* has_global_breakpoints */
default_has_shared_address_space, /* has_shared_address_space */
@@ -715,6 +735,16 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of get_siginfo_type, has predicate. */
/* Skip verify of record_special_symbol, has predicate. */
/* Skip verify of get_syscall_number, has predicate. */
+ /* Skip verify of stap_integer_prefix, invalid_p == 0 */
+ /* Skip verify of stap_integer_suffix, invalid_p == 0 */
+ /* Skip verify of stap_register_prefix, invalid_p == 0 */
+ /* Skip verify of stap_register_suffix, invalid_p == 0 */
+ /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */
+ /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */
+ /* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */
+ /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
+ /* Skip verify of stap_is_single_operand, has predicate. */
+ /* Skip verify of stap_parse_special_token, has predicate. */
/* Skip verify of has_global_solist, invalid_p == 0 */
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
/* Skip verify of has_shared_address_space, invalid_p == 0 */
@@ -1267,6 +1297,42 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: stabs_argument_has_addr = <%s>\n",
host_address_to_string (gdbarch->stabs_argument_has_addr));
fprintf_unfiltered (file,
+ "gdbarch_dump: stap_gdb_register_prefix = %s\n",
+ gdbarch->stap_gdb_register_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_gdb_register_suffix = %s\n",
+ gdbarch->stap_gdb_register_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_integer_prefix = %s\n",
+ gdbarch->stap_integer_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_integer_suffix = %s\n",
+ gdbarch->stap_integer_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_stap_is_single_operand_p() = %d\n",
+ gdbarch_stap_is_single_operand_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_is_single_operand = <%s>\n",
+ host_address_to_string (gdbarch->stap_is_single_operand));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_stap_parse_special_token_p() = %d\n",
+ gdbarch_stap_parse_special_token_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_parse_special_token = <%s>\n",
+ host_address_to_string (gdbarch->stap_parse_special_token));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_indirection_prefix = %s\n",
+ gdbarch->stap_register_indirection_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_indirection_suffix = %s\n",
+ gdbarch->stap_register_indirection_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_prefix = %s\n",
+ gdbarch->stap_register_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_suffix = %s\n",
+ gdbarch->stap_register_suffix);
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_static_transform_name_p() = %d\n",
gdbarch_static_transform_name_p (gdbarch));
fprintf_unfiltered (file,
@@ -3834,6 +3900,190 @@ set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
gdbarch->get_syscall_number = get_syscall_number;
}
+const char *
+gdbarch_stap_integer_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_integer_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_prefix called\n");
+ return gdbarch->stap_integer_prefix;
+}
+
+void
+set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch,
+ const char * stap_integer_prefix)
+{
+ gdbarch->stap_integer_prefix = stap_integer_prefix;
+}
+
+const char *
+gdbarch_stap_integer_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_integer_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_suffix called\n");
+ return gdbarch->stap_integer_suffix;
+}
+
+void
+set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch,
+ const char * stap_integer_suffix)
+{
+ gdbarch->stap_integer_suffix = stap_integer_suffix;
+}
+
+const char *
+gdbarch_stap_register_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_prefix called\n");
+ return gdbarch->stap_register_prefix;
+}
+
+void
+set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch,
+ const char * stap_register_prefix)
+{
+ gdbarch->stap_register_prefix = stap_register_prefix;
+}
+
+const char *
+gdbarch_stap_register_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_suffix called\n");
+ return gdbarch->stap_register_suffix;
+}
+
+void
+set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch,
+ const char * stap_register_suffix)
+{
+ gdbarch->stap_register_suffix = stap_register_suffix;
+}
+
+const char *
+gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_prefix called\n");
+ return gdbarch->stap_register_indirection_prefix;
+}
+
+void
+set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch,
+ const char * stap_register_indirection_prefix)
+{
+ gdbarch->stap_register_indirection_prefix = stap_register_indirection_prefix;
+}
+
+const char *
+gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_suffix called\n");
+ return gdbarch->stap_register_indirection_suffix;
+}
+
+void
+set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch,
+ const char * stap_register_indirection_suffix)
+{
+ gdbarch->stap_register_indirection_suffix = stap_register_indirection_suffix;
+}
+
+const char *
+gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_gdb_register_prefix called\n");
+ return gdbarch->stap_gdb_register_prefix;
+}
+
+void
+set_gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch,
+ const char * stap_gdb_register_prefix)
+{
+ gdbarch->stap_gdb_register_prefix = stap_gdb_register_prefix;
+}
+
+const char *
+gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_gdb_register_suffix called\n");
+ return gdbarch->stap_gdb_register_suffix;
+}
+
+void
+set_gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch,
+ const char * stap_gdb_register_suffix)
+{
+ gdbarch->stap_gdb_register_suffix = stap_gdb_register_suffix;
+}
+
+int
+gdbarch_stap_is_single_operand_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->stap_is_single_operand != NULL;
+}
+
+int
+gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stap_is_single_operand != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_is_single_operand called\n");
+ return gdbarch->stap_is_single_operand (gdbarch, s);
+}
+
+void
+set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch,
+ gdbarch_stap_is_single_operand_ftype stap_is_single_operand)
+{
+ gdbarch->stap_is_single_operand = stap_is_single_operand;
+}
+
+int
+gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->stap_parse_special_token != NULL;
+}
+
+int
+gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stap_parse_special_token != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_parse_special_token called\n");
+ return gdbarch->stap_parse_special_token (gdbarch, p);
+}
+
+void
+set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
+ gdbarch_stap_parse_special_token_ftype stap_parse_special_token)
+{
+ gdbarch->stap_parse_special_token = stap_parse_special_token;
+}
+
int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 84e6ff8..2d832aa 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -55,6 +55,7 @@ struct core_regset_section;
struct syscall;
struct agent_expr;
struct axs_value;
+struct stap_parse_info;
/* The architecture associated with the connection to the target.
@@ -979,6 +980,125 @@ typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, pti
extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
+/* SystemTap related fields and functions.
+ Prefix used to mark an integer constant on the architecture's assembly
+ For example, on x86 integer constants are written as:
+
+ $10 ;; integer constant 10
+
+ in this case, this prefix would be the character `$'. */
+
+extern const char * gdbarch_stap_integer_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch, const char * stap_integer_prefix);
+
+/* Suffix used to mark an integer constant on the architecture's assembly. */
+
+extern const char * gdbarch_stap_integer_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch, const char * stap_integer_suffix);
+
+/* Prefix used to mark a register name on the architecture's assembly.
+ For example, on x86 the register name is written as:
+
+ %eax ;; register eax
+
+ in this case, this prefix would be the character `%'. */
+
+extern const char * gdbarch_stap_register_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch, const char * stap_register_prefix);
+
+/* Suffix used to mark a register name on the architecture's assembly */
+
+extern const char * gdbarch_stap_register_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch, const char * stap_register_suffix);
+
+/* Prefix used to mark a register indirection on the architecture's assembly.
+ For example, on x86 the register indirection is written as:
+
+ (%eax) ;; indirecting eax
+
+ in this case, this prefix would be the charater `('.
+
+ Please note that we use the indirection prefix also for register
+ displacement, e.g., `4(%eax)' on x86. */
+
+extern const char * gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch, const char * stap_register_indirection_prefix);
+
+/* Suffix used to mark a register indirection on the architecture's assembly.
+ For example, on x86 the register indirection is written as:
+
+ (%eax) ;; indirecting eax
+
+ in this case, this prefix would be the charater `)'.
+
+ Please note that we use the indirection suffix also for register
+ displacement, e.g., `4(%eax)' on x86. */
+
+extern const char * gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch, const char * stap_register_indirection_suffix);
+
+/* Prefix used to name a register using GDB's nomenclature.
+
+ For example, on PPC a register is represented by a number in the assembly
+ language (e.g., `10' is the 10th general-purpose register). However,
+ inside GDB this same register has an `r' appended to its name, so the 10th
+ register would be represented as `r10' internally. */
+
+extern const char * gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch, const char * stap_gdb_register_prefix);
+
+/* Suffix used to name a register using GDB's nomenclature. */
+
+extern const char * gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch, const char * stap_gdb_register_suffix);
+
+/* Check if S is a single operand.
+
+ Single operands can be:
+ - Literal integers, e.g. `$10' on x86
+ - Register access, e.g. `%eax' on x86
+ - Register indirection, e.g. `(%eax)' on x86
+ - Register displacement, e.g. `4(%eax)' on x86
+
+ This function should check for these patterns on the string
+ and return 1 if some were found, or zero otherwise. Please try to match
+ as much info as you can from the string, i.e., if you have to match
+ something like `(%', do not match just the `('. */
+
+extern int gdbarch_stap_is_single_operand_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_stap_is_single_operand_ftype) (struct gdbarch *gdbarch, const char *s);
+extern int gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, const char *s);
+extern void set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, gdbarch_stap_is_single_operand_ftype *stap_is_single_operand);
+
+/* Function used to handle a "special case" in the parser.
+
+ A "special case" is considered to be an unknown token, i.e., a token
+ that the parser does not know how to parse. A good example of special
+ case would be ARM's register displacement syntax:
+
+ [R0, #4] ;; displacing R0 by 4
+
+ Since the parser assumes that a register displacement is of the form:
+
+ <number> <indirection_prefix> <register_name> <indirection_suffix>
+
+ it means that it will not be able to recognize and parse this odd syntax.
+ Therefore, we should add a special case function that will handle this token.
+
+ This function should generate the proper expression form of the expression
+ using GDB's internal expression mechanism (e.g., `write_exp_elt_opcode'
+ and so on). It should also return 1 if the parsing was successful, or zero
+ if the token was not recognized as a special token (in this case, returning
+ zero means that the special parser is deferring the parsing to the generic
+ parser), and should advance the buffer pointer (p->arg). */
+
+extern int gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p);
+extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
+extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token);
+
/* True if the list of shared libraries is one and only for all
processes, as opposed to a list of shared libraries per inferior.
This usually means that all processes, although may or may not share
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 5831172..956734a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -792,6 +792,101 @@ M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
# Get architecture-specific system calls information from registers.
M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+# SystemTap related fields and functions.
+
+# Prefix used to mark an integer constant on the architecture's assembly
+# For example, on x86 integer constants are written as:
+#
+# \$10 ;; integer constant 10
+#
+# in this case, this prefix would be the character \`\$\'.
+v:const char *:stap_integer_prefix:::0:0::0:gdbarch->stap_integer_prefix
+
+# Suffix used to mark an integer constant on the architecture's assembly.
+v:const char *:stap_integer_suffix:::0:0::0:gdbarch->stap_integer_suffix
+
+# Prefix used to mark a register name on the architecture's assembly.
+# For example, on x86 the register name is written as:
+#
+# \%eax ;; register eax
+#
+# in this case, this prefix would be the character \`\%\'.
+v:const char *:stap_register_prefix:::0:0::0:gdbarch->stap_register_prefix
+
+# Suffix used to mark a register name on the architecture's assembly
+v:const char *:stap_register_suffix:::0:0::0:gdbarch->stap_register_suffix
+
+# Prefix used to mark a register indirection on the architecture's assembly.
+# For example, on x86 the register indirection is written as:
+#
+# \(\%eax\) ;; indirecting eax
+#
+# in this case, this prefix would be the charater \`\(\'.
+#
+# Please note that we use the indirection prefix also for register
+# displacement, e.g., \`4\(\%eax\)\' on x86.
+v:const char *:stap_register_indirection_prefix:::0:0::0:gdbarch->stap_register_indirection_prefix
+
+# Suffix used to mark a register indirection on the architecture's assembly.
+# For example, on x86 the register indirection is written as:
+#
+# \(\%eax\) ;; indirecting eax
+#
+# in this case, this prefix would be the charater \`\)\'.
+#
+# Please note that we use the indirection suffix also for register
+# displacement, e.g., \`4\(\%eax\)\' on x86.
+v:const char *:stap_register_indirection_suffix:::0:0::0:gdbarch->stap_register_indirection_suffix
+
+# Prefix used to name a register using GDB's nomenclature.
+#
+# For example, on PPC a register is represented by a number in the assembly
+# language (e.g., \`10\' is the 10th general-purpose register). However,
+# inside GDB this same register has an \`r\' appended to its name, so the 10th
+# register would be represented as \`r10\' internally.
+v:const char *:stap_gdb_register_prefix:::0:0::0:gdbarch->stap_gdb_register_prefix
+
+# Suffix used to name a register using GDB's nomenclature.
+v:const char *:stap_gdb_register_suffix:::0:0::0:gdbarch->stap_gdb_register_suffix
+
+# Check if S is a single operand.
+#
+# Single operands can be:
+# \- Literal integers, e.g. \`\$10\' on x86
+# \- Register access, e.g. \`\%eax\' on x86
+# \- Register indirection, e.g. \`\(\%eax\)\' on x86
+# \- Register displacement, e.g. \`4\(\%eax\)\' on x86
+#
+# This function should check for these patterns on the string
+# and return 1 if some were found, or zero otherwise. Please try to match
+# as much info as you can from the string, i.e., if you have to match
+# something like \`\(\%\', do not match just the \`\(\'.
+M:int:stap_is_single_operand:const char *s:s
+
+# Function used to handle a "special case" in the parser.
+#
+# A "special case" is considered to be an unknown token, i.e., a token
+# that the parser does not know how to parse. A good example of special
+# case would be ARM's register displacement syntax:
+#
+# [R0, #4] ;; displacing R0 by 4
+#
+# Since the parser assumes that a register displacement is of the form:
+#
+# <number> <indirection_prefix> <register_name> <indirection_suffix>
+#
+# it means that it will not be able to recognize and parse this odd syntax.
+# Therefore, we should add a special case function that will handle this token.
+#
+# This function should generate the proper expression form of the expression
+# using GDB\'s internal expression mechanism (e.g., \`write_exp_elt_opcode\'
+# and so on). It should also return 1 if the parsing was successful, or zero
+# if the token was not recognized as a special token (in this case, returning
+# zero means that the special parser is deferring the parsing to the generic
+# parser), and should advance the buffer pointer (p->arg).
+M:int:stap_parse_special_token:struct stap_parse_info *p:p
+
+
# True if the list of shared libraries is one and only for all
# processes, as opposed to a list of shared libraries per inferior.
# This usually means that all processes, although may or may not share
@@ -954,6 +1049,7 @@ struct core_regset_section;
struct syscall;
struct agent_expr;
struct axs_value;
+struct stap_parse_info;
/* The architecture associated with the connection to the target.
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index d18aa99..769ef42 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -61,6 +61,13 @@
#include "ax.h"
#include "ax-gdb.h"
+#include "stap-probe.h"
+#include "user-regs.h"
+#include "cli/cli-utils.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include <ctype.h>
+
/* Register names. */
static const char *i386_register_names[] =
@@ -3363,6 +3370,325 @@ i386_svr4_sigcontext_addr (struct frame_info *this_frame)
return read_memory_unsigned_integer (sp + 8, 4, byte_order);
}
+
+\f
+
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+ gdbarch.h. */
+
+int
+i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == '$' /* Literal number. */
+ || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement. */
+ || (*s == '(' && s[1] == '%') /* Register indirection. */
+ || (*s == '%' && isalpha (s[1]))); /* Register access. */
+}
+
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+ gdbarch.h. */
+
+int
+i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ const char *s = p->arg;
+
+ /* In order to parse special tokens, we use a state-machine that go
+ through every known token and try to get a match. */
+ enum
+ {
+ TRIPLET,
+ THREE_ARG_DISPLACEMENT,
+ DONE
+ } current_state;
+
+ current_state = TRIPLET;
+
+ /* The special tokens to be parsed here are:
+
+ - `register base + (register index * size) + offset', as represented
+ in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
+
+ - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
+ `*(-8 + 3 - 1 + (void *) $eax)'. */
+
+ while (current_state != DONE)
+ {
+ const char *s = p->arg;
+
+ switch (current_state)
+ {
+ case TRIPLET:
+ {
+ if (isdigit (*s) || *s == '-' || *s == '+')
+ {
+ int got_minus[3];
+ int i;
+ long displacements[3];
+ const char *start;
+ char *regname;
+ int len;
+ struct stoken str;
+
+ got_minus[0] = 0;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ got_minus[0] = 1;
+ }
+
+ displacements[0] = strtol (s, (char **) &s, 10);
+
+ if (*s != '+' && *s != '-')
+ {
+ /* We are not dealing with a triplet. */
+ break;
+ }
+
+ got_minus[1] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[1] = 1;
+ }
+
+ displacements[1] = strtol (s, (char **) &s, 10);
+
+ if (*s != '+' && *s != '-')
+ {
+ /* We are not dealing with a triplet. */
+ break;
+ }
+
+ got_minus[2] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[2] = 1;
+ }
+
+ displacements[2] = strtol (s, (char **) &s, 10);
+
+ if (*s != '(' || s[1] != '%')
+ break;
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ if (*s++ != ')')
+ break;
+
+ len = s - start;
+ regname = alloca (len + 1);
+
+ strncpy (regname, start, len);
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ regname, len) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ regname, p->saved_arg);
+
+ for (i = 0; i < 3; i++)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacements[i]);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus[i])
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = s;
+
+ return 1;
+ }
+ break;
+ }
+ case THREE_ARG_DISPLACEMENT:
+ {
+ if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
+ {
+ int offset_minus = 0;
+ long offset = 0;
+ int size_minus = 0;
+ long size = 0;
+ const char *start;
+ char *base;
+ int len_base;
+ char *index;
+ int len_index;
+ struct stoken base_token, index_token;
+
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ offset_minus = 1;
+ }
+
+ if (offset_minus && !isdigit (*s))
+ break;
+
+ if (isdigit (*s))
+ offset = strtol (s, (char **) &s, 10);
+
+ if (*s != '(' || s[1] != '%')
+ break;
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ if (*s != ',' || s[1] != '%')
+ break;
+
+ len_base = s - start;
+ base = alloca (len_base + 1);
+ strncpy (base, start, len_base);
+ base[len_base] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ base, len_base) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ base, p->saved_arg);
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ len_index = s - start;
+ index = alloca (len_index + 1);
+ strncpy (index, start, len_index);
+ index[len_index] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ index, len_index) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ index, p->saved_arg);
+
+ if (*s != ',' && *s != ')')
+ break;
+
+ if (*s == ',')
+ {
+ ++s;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ size_minus = 1;
+ }
+
+ size = strtol (s, (char **) &s, 10);
+
+ if (*s != ')')
+ break;
+ }
+
+ ++s;
+
+ if (offset)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (offset);
+ write_exp_elt_opcode (OP_LONG);
+ if (offset_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ write_exp_elt_opcode (OP_REGISTER);
+ base_token.ptr = base;
+ base_token.length = len_base;
+ write_exp_string (base_token);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (offset)
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ index_token.ptr = index;
+ index_token.length = len_index;
+ write_exp_string (index_token);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (size)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (size);
+ write_exp_elt_opcode (OP_LONG);
+ if (size_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ write_exp_elt_opcode (BINOP_MUL);
+ }
+
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = s;
+
+ return 1;
+ }
+ break;
+ }
+ }
+
+ /* Advancing to the next state. */
+ ++current_state;
+ }
+
+ return 0;
+}
+
\f
/* Generic ELF. */
@@ -3372,6 +3698,16 @@ i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
/* We typically use stabs-in-ELF with the SVR4 register numbering. */
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+ /* Registering SystemTap handlers. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "$");
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch,
+ i386_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ i386_stap_parse_special_token);
}
/* System V Release 4 (SVR4). */
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 870054f..f297ae7 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -379,6 +379,7 @@ extern void i386_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
extern int i386_process_record (struct gdbarch *gdbarch,
struct regcache *regcache, CORE_ADDR addr);
+
\f
/* Functions and variables exported from i386bsd-tdep.c. */
@@ -394,4 +395,12 @@ extern int i386nbsd_sc_reg_offset[];
extern int i386obsd_sc_reg_offset[];
extern int i386bsd_sc_reg_offset[];
+/* SystemTap related functions. */
+
+extern int i386_stap_is_single_operand (struct gdbarch *gdbarch,
+ const char *s);
+
+extern int i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p);
+
#endif /* i386-tdep.h */
diff --git a/gdb/machoread.c b/gdb/machoread.c
index 8a6b500..1986f54 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -1032,6 +1032,7 @@ static const struct sym_fns macho_sym_fns = {
default_symfile_segments, /* Get segment information from a file. */
NULL,
macho_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index 5790730..23ceece 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -401,6 +401,7 @@ static const struct sym_fns ecoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index e29b3a7..1f4913a 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -795,6 +795,11 @@ objfile_relocate1 (struct objfile *objfile,
obj_section_addr (s));
}
+ /* Relocating probes. */
+ if (objfile->sf && objfile->sf->sym_probe_fns)
+ objfile->sf->sym_probe_fns->sym_relocate_probe (objfile,
+ new_offsets, delta);
+
/* Data changed. */
return 1;
}
diff --git a/gdb/parse.c b/gdb/parse.c
index 32a3bd6..79b2e21 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -113,8 +113,6 @@ show_parserdebug (struct ui_file *file, int from_tty,
static void free_funcalls (void *ignore);
-static int prefixify_expression (struct expression *);
-
static int prefixify_subexp (struct expression *, struct expression *, int,
int);
@@ -182,13 +180,9 @@ free_funcalls (void *ignore)
/* This page contains the functions for adding data to the struct expression
being constructed. */
-/* Helper function to initialize the expout, expout_size, expout_ptr
- trio before it is used to store expression elements created during
- the parsing of an expression. INITIAL_SIZE is the initial size of
- the expout array. LANG is the language used to parse the expression.
- And GDBARCH is the gdbarch to use during parsing. */
+/* See definition in parser-defs.h. */
-static void
+void
initialize_expout (int initial_size, const struct language_defn *lang,
struct gdbarch *gdbarch)
{
@@ -200,11 +194,9 @@ initialize_expout (int initial_size, const struct language_defn *lang,
expout->gdbarch = gdbarch;
}
-/* Helper function that frees any unsed space in the expout array.
- It is generally used when the parser has just been parsed and
- created. */
+/* See definition in parser-defs.h. */
-static void
+void
reallocate_expout (void)
{
/* Record the actual number of expression elements, and then
@@ -804,14 +796,10 @@ copy_name (struct stoken token)
return namecopy;
}
\f
-/* Reverse an expression from suffix form (in which it is constructed)
- to prefix form (in which we can conveniently print or execute it).
- Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT
- is not -1 (i.e., we are trying to complete a field name), it will
- return the index of the subexpression which is the left-hand-side
- of the struct operation at EXPOUT_LAST_STRUCT. */
-static int
+/* See comments on parser-defs.h. */
+
+int
prefixify_expression (struct expression *expr)
{
int len = sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 16b40ac..72b9e2f 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -130,6 +130,30 @@ union type_stack_elt
extern union type_stack_elt *type_stack;
extern int type_stack_depth, type_stack_size;
+/* Helper function to initialize the expout, expout_size, expout_ptr
+ trio before it is used to store expression elements created during
+ the parsing of an expression. INITIAL_SIZE is the initial size of
+ the expout array. LANG is the language used to parse the expression.
+ And GDBARCH is the gdbarch to use during parsing. */
+
+extern void initialize_expout (int, const struct language_defn *,
+ struct gdbarch *);
+
+/* Helper function that frees any unsed space in the expout array.
+ It is generally used when the parser has just been parsed and
+ created. */
+
+extern void reallocate_expout (void);
+
+/* Reverse an expression from suffix form (in which it is constructed)
+ to prefix form (in which we can conveniently print or execute it).
+ Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT
+ is not -1 (i.e., we are trying to complete a field name), it will
+ return the index of the subexpression which is the left-hand-side
+ of the struct operation at EXPOUT_LAST_STRUCT. */
+
+extern int prefixify_expression (struct expression *expr);
+
extern void write_exp_elt_opcode (enum exp_opcode);
extern void write_exp_elt_sym (struct symbol *);
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index b94dea2..3392e67 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -50,6 +50,14 @@
#include "xml-syscall.h"
#include "linux-tdep.h"
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "cli/cli-utils.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
#include "features/rs6000/powerpc-cell32l.c"
@@ -1276,6 +1284,75 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
}
}
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+ gdbarch.h. */
+
+static int
+ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == 'i' /* Literal number. */
+ || (isdigit (*s) && s[1] == '('
+ && isdigit (s[2])) /* Displacement. */
+ || (*s == '(' && isdigit (s[1])) /* Register indirection. */
+ || isdigit (*s)); /* Register value. */
+}
+
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+ gdbarch.h. */
+
+static int
+ppc_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ if (isdigit (*p->arg))
+ {
+ /* This temporary pointer is needed because we have to do a lookahead.
+ We could be dealing with a register displacement, and in such case
+ we would not need to do anything. */
+ const char *s = p->arg;
+ char *regname;
+ int len;
+ struct stoken str;
+
+ while (isdigit (*s))
+ ++s;
+
+ if (*s == '(')
+ {
+ /* It is a register displacement indeed. Returning 0 means we are
+ deferring the treatment of this case to the generic parser. */
+ return 0;
+ }
+
+ len = s - p->arg;
+ regname = alloca (len + 2);
+ regname[0] = 'r';
+
+ strncpy (regname + 1, p->arg, len);
+ ++len;
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ p->arg = s;
+ }
+ else
+ {
+ /* All the other tokens should be handled correctly by the generic
+ parser. */
+ return 0;
+ }
+
+ return 1;
+}
/* Cell/B.E. active SPE context tracking support. */
@@ -1593,6 +1670,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Get the syscall number from the arch's register. */
set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+ /* SystemTap functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "i");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ ppc_stap_parse_special_token);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
diff --git a/gdb/probe.c b/gdb/probe.c
new file mode 100644
index 0000000..4e1b6a0
--- /dev/null
+++ b/gdb/probe.c
@@ -0,0 +1,788 @@
+/* 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>
+
+\f
+
+/* 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;
+
+ if (objfile->separate_debug_objfile_backlink != NULL)
+ 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;
+}
+
+\f
+
+/* 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 ());
+}
diff --git a/gdb/probe.h b/gdb/probe.h
new file mode 100644
index 0000000..8d44ca2
--- /dev/null
+++ b/gdb/probe.h
@@ -0,0 +1,221 @@
+/* Generic SDT 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/>. */
+
+#if !defined (PROBE_H)
+#define PROBE_H 1
+
+#include "gdb_vecs.h"
+
+struct linespec_result;
+
+/* Structure useful for passing the header names in the method
+ `gen_ui_out_table_header'. */
+
+struct info_probe_column
+ {
+ /* The internal name of the field. This string cannot be capitalized nor
+ localized, e.g., "extra_field". */
+
+ const char *field_name;
+
+ /* The field name to be printed in the `info probes' command. This
+ string can be capitalized and localized, e.g., _("Extra Field"). */
+ const char *print_name;
+ };
+
+typedef struct info_probe_column info_probe_column_s;
+DEF_VEC_O (info_probe_column_s);
+
+/* Operations associated with a probe. */
+
+struct probe_ops
+ {
+ /* Method responsible for verifying if LINESPECP is a valid linespec for
+ a probe breakpoint. It should return 1 if it is, or zero if it is not.
+ It also should update LINESPECP in order to discard the breakpoint
+ option associated with this linespec. For example, if the option is
+ `-probe', and the LINESPECP is `-probe abc', the function should
+ return 1 and set LINESPECP to `abc'. */
+
+ int (*is_linespec) (const char **linespecp);
+
+ /* Function that should fill PROBES with known probes from OBJFILE. */
+
+ void (*get_probes) (VEC (probe_p) **probes, struct objfile *objfile);
+
+ /* Function used to relocate addresses from PROBE according to some DELTA
+ provided. */
+
+ void (*relocate) (struct probe *probe, CORE_ADDR delta);
+
+ /* Return the number of arguments of PROBE. */
+
+ unsigned (*get_probe_argument_count) (struct probe *probe,
+ struct objfile *objfile);
+
+ /* Evaluate the Nth argument from the PROBE, returning a value
+ corresponding to it. The argument number is represented N. */
+
+ struct value *(*evaluate_probe_argument) (struct probe *probe,
+ struct objfile *objfile,
+ unsigned n);
+
+ /* Compile the Nth argument of the PROBE to an agent expression.
+ The argument number is represented by N. */
+
+ void (*compile_to_ax) (struct probe *probe, struct objfile *objfile,
+ struct agent_expr *aexpr,
+ struct axs_value *axs_value, unsigned n);
+
+ /* Set the semaphore associated with the PROBE. This function only makes
+ sense if the probe has a concept of semaphore associated to a
+ probe. */
+
+ void (*set_semaphore) (struct probe *probe, struct gdbarch *gdbarch);
+
+ /* Clear the semaphore associated with the PROBE. This function only
+ makes sense if the probe has a concept of semaphore associated to
+ a probe. */
+
+ void (*clear_semaphore) (struct probe *probe, struct gdbarch *gdbarch);
+
+ /* Function called to destroy PROBE's specific data. This function
+ shall not free PROBE itself. */
+
+ void (*destroy) (struct probe *probe);
+
+ /* Function responsible for providing the extra fields that will be
+ printed in the `info probes' command. It should fill HEADS
+ with whatever extra fields it needs. If the backend doesn't need
+ to print extra fields, it can set this method to NULL. */
+
+ void (*gen_info_probes_table_header) (VEC (info_probe_column_s) **heads);
+
+ /* Function that will fill VALUES with the values of the extra fields
+ to be printed for PROBE and OBJFILE. If the backend implements
+ the `gen_ui_out_table_header' method, then it should implement
+ this method as well. The backend should also guarantee that the
+ order and the number of values in the vector is exactly the same
+ as the order of the extra fields provided in the method
+ `gen_ui_out_table_header'. If a certain field is to be skipped
+ when printing the information, you can push a NULL value in that
+ position in the vector. */
+
+ void (*gen_info_probes_table_values) (struct probe *probe,
+ struct objfile *objfile,
+ VEC (const_char_ptr) **values);
+ };
+
+/* Definition of a vector of probe_ops. */
+
+typedef const struct probe_ops *probe_ops_cp;
+DEF_VEC_P (probe_ops_cp);
+extern VEC (probe_ops_cp) *all_probe_ops;
+
+/* The probe_ops associated with the generic probe. */
+
+extern const struct probe_ops probe_ops_any;
+
+/* Helper function that, given KEYWORDS, iterate over it trying to match
+ each keyword with LINESPECP. If it succeeds, it updates the LINESPECP
+ pointer and returns 1. Otherwise, nothing is done to LINESPECP and zero
+ is returned. */
+
+extern int probe_is_linespec_by_keyword (const char **linespecp,
+ const char *const *keywords);
+
+/* Return specific PROBE_OPS * matching *LINESPECP and possibly updating
+ *LINESPECP to skip its "-probe-type " prefix. Return &probe_ops_any if
+ *LINESPECP matches "-probe ", that is any unspecific probe. Return NULL if
+ *LINESPECP is not identified as any known probe type, *LINESPECP is not
+ modified in such case. */
+
+extern const struct probe_ops *probe_linespec_to_ops (const char **linespecp);
+
+/* The probe itself. The struct contains generic information about the
+ probe, and then some specific information which should be stored in
+ the `probe_info' field. */
+
+struct probe
+ {
+ /* The operations associated with this probe. */
+ const struct probe_ops *pops;
+
+ /* The name of the probe. */
+ const char *name;
+
+ /* The provider of the probe. It generally defaults to the name of
+ the objfile which contains the probe. */
+ const char *provider;
+
+ /* The address where the probe is inserted. */
+ CORE_ADDR address;
+ };
+
+/* A helper for linespec that decodes a probe specification. It returns a
+ symtabs_and_lines object and updates *ARGPTR or throws an error. The
+ argument PTYPE specifies the type of the probe(s) to be parsed. */
+
+extern struct symtabs_and_lines parse_probes (char **argptr,
+ struct linespec_result *canon);
+
+/* Helper function to register the proper probe_ops to a newly created probe.
+ This function is mainly called from `sym_get_probes'. */
+
+extern void register_probe_ops (struct probe *probe);
+
+/* Given a PC, find an associated probe with type PTYPE. If a probe is
+ found, set *OBJFILE_OUT to the probe's objfile, and return the
+ probe. If no probe is found, return NULL. */
+
+extern struct probe *find_probe_by_pc (CORE_ADDR pc,
+ struct objfile **objfile_out);
+
+/* Search OBJFILE for a probe with the given PROVIDER, NAME and PTYPE.
+ Return a VEC of all probes that were found. If no matching probe
+ is found, return NULL. The caller must free the VEC. */
+
+extern VEC (probe_p) *find_probes_in_objfile (struct objfile *objfile,
+ const char *provider,
+ const char *name);
+
+/* Generate a `info probes' command output for probe_ops represented by
+ POPS. If POPS is NULL it considers any probes types. It is a helper
+ function that can be used by the probe backends to print their
+ `info probe TYPE'. */
+
+extern void info_probes_for_ops (char *arg, int from_tty,
+ const struct probe_ops *pops);
+
+/* Return the `cmd_list_element' associated with the `info probes' command,
+ or create a new one if it doesn't exist. Helper function that serves the
+ purpose of avoiding the case of a backend using the `cmd_list_element'
+ associated with `info probes', without having it registered yet. */
+
+extern struct cmd_list_element **info_probes_cmdlist_get (void);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+ evaluates argument N, with 0 <= N < number_of_args. If there is no
+ probe at that location, or if the probe does not have enough arguments,
+ this returns NULL. */
+
+extern struct value *probe_safe_evaluate_at_pc (struct frame_info *frame,
+ unsigned n);
+
+#endif /* !defined (PROBE_H) */
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index ac0c526..038a3ce 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -45,6 +45,13 @@
#include "linux-tdep.h"
#include "s390-tdep.h"
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "user-regs.h"
+#include "cli/cli-utils.h"
+#include <ctype.h>
+
#include "features/s390-linux32.c"
#include "features/s390-linux32v1.c"
#include "features/s390-linux32v2.c"
@@ -55,7 +62,6 @@
#include "features/s390x-linux64v1.c"
#include "features/s390x-linux64v2.c"
-
/* The tdep structure. */
struct gdbarch_tdep
@@ -2953,6 +2959,18 @@ s390_address_class_name_to_type_flags (struct gdbarch *gdbarch,
return 0;
}
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+ gdbarch.h. */
+
+static int
+s390_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return ((isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement
+ or indirection. */
+ || *s == '%' /* Register access. */
+ || isdigit (*s)); /* Literal number. */
+}
+
/* Set up gdbarch struct. */
static struct gdbarch *
@@ -3283,6 +3301,12 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+ /* SystemTap functions. */
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch, s390_stap_is_single_operand);
+
return gdbarch;
}
diff --git a/gdb/somread.c b/gdb/somread.c
index e621cba..19a15e2 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -427,6 +427,7 @@ static const struct sym_fns som_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
new file mode 100644
index 0000000..13ba281
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,1558 @@
+/* SystemTap 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 "stap-probe.h"
+#include "probe.h"
+#include "vec.h"
+#include "ui-out.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "filenames.h"
+#include "value.h"
+#include "exceptions.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "complaints.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
+#include "user-regs.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "elf-bfd.h"
+
+#include <ctype.h>
+
+/* The name of the SystemTap section where we will find information about
+ the probes. */
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
+/* Forward declaration. */
+
+static const struct probe_ops stap_probe_ops;
+
+/* Should we display debug information for the probe's argument expression
+ parsing? */
+
+static int stap_expression_debug = 0;
+
+/* The various possibilities of bitness defined for a probe's argument.
+
+ The relationship is:
+
+ - STAP_ARG_BITNESS_UNDEFINED: The user hasn't specified the bitness.
+ - STAP_ARG_BITNESS_32BIT_UNSIGNED: argument string starts with `4@'.
+ - STAP_ARG_BITNESS_32BIT_SIGNED: argument string starts with `-4@'.
+ - STAP_ARG_BITNESS_64BIT_UNSIGNED: argument string starts with `8@'.
+ - STAP_ARG_BITNESS_64BIT_SIGNED: argument string starts with `-8@'. */
+
+enum stap_arg_bitness
+{
+ STAP_ARG_BITNESS_UNDEFINED,
+ STAP_ARG_BITNESS_32BIT_UNSIGNED,
+ STAP_ARG_BITNESS_32BIT_SIGNED,
+ STAP_ARG_BITNESS_64BIT_UNSIGNED,
+ STAP_ARG_BITNESS_64BIT_SIGNED,
+};
+
+/* The following structure represents a single argument for the probe. */
+
+struct stap_probe_arg
+{
+ /* The bitness of this argument. */
+ enum stap_arg_bitness bitness;
+
+ /* The corresponding `struct type *' to the bitness. */
+ struct type *atype;
+
+ /* The argument converted to an internal GDB expression. */
+ struct expression *aexpr;
+};
+
+typedef struct stap_probe_arg stap_probe_arg_s;
+DEF_VEC_O (stap_probe_arg_s);
+
+struct stap_probe
+{
+ /* Generic information about the probe. This shall be the first element
+ of this struct, in order to maintain binary compatibility with the
+ `struct probe' and be able to fully abstract it. */
+ struct probe p;
+
+ /* If the probe has a semaphore associated, then this is the value of
+ it. */
+ CORE_ADDR sem_addr;
+
+ unsigned int args_parsed : 1;
+ union
+ {
+ const char *text;
+
+ /* Information about each argument. This is an array of `stap_probe_arg',
+ with each entry representing one argument. */
+ VEC (stap_probe_arg_s) *vec;
+ }
+ args_u;
+};
+
+/* When parsing the arguments, we have to establish different precedences
+ for the various kinds of asm operators. This enumeration represents those
+ precedences.
+
+ This logic behind this is available at
+ <http://sourceware.org/binutils/docs/as/Infix-Ops.html#Infix-Ops>, or using
+ the command "info '(as)Infix Ops'". */
+
+enum stap_operand_prec
+{
+ /* Lowest precedence, used for non-recognized operands or for the beginning
+ of the parsing process. */
+ STAP_OPERAND_PREC_NONE = 0,
+
+ /* Precedence of logical OR. */
+ STAP_OPERAND_PREC_LOGICAL_OR,
+
+ /* Precedence of logical AND. */
+ STAP_OPERAND_PREC_LOGICAL_AND,
+
+ /* Precedence of additive (plus, minus) and comparative (equal, less,
+ greater-than, etc) operands. */
+ STAP_OPERAND_PREC_ADD_CMP,
+
+ /* Precedence of bitwise operands (bitwise OR, XOR, bitwise AND,
+ logical NOT). */
+ STAP_OPERAND_PREC_BITWISE,
+
+ /* Precedence of multiplicative operands (multiplication, division,
+ remainder, left shift and right shift). */
+ STAP_OPERAND_PREC_MUL
+};
+
+static void stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
+ enum stap_operand_prec prec);
+
+static void stap_parse_argument_conditionally (struct stap_parse_info *p);
+
+/* Returns 1 if *S is an operator, zero otherwise. */
+
+static int stap_is_operator (char op);
+
+static void
+show_stapexpressiondebug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("SystemTap Probe expression debugging is %s.\n"),
+ value);
+}
+
+/* Returns the operator precedence level of OP, or STAP_OPERAND_PREC_NONE
+ if the operator code was not recognized. */
+
+static enum stap_operand_prec
+stap_get_operator_prec (enum exp_opcode op)
+{
+ switch (op)
+ {
+ case BINOP_LOGICAL_OR:
+ return STAP_OPERAND_PREC_LOGICAL_OR;
+
+ case BINOP_LOGICAL_AND:
+ return STAP_OPERAND_PREC_LOGICAL_AND;
+
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_LEQ:
+ case BINOP_GTR:
+ case BINOP_GEQ:
+ return STAP_OPERAND_PREC_ADD_CMP;
+
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_XOR:
+ case UNOP_LOGICAL_NOT:
+ return STAP_OPERAND_PREC_BITWISE;
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ return STAP_OPERAND_PREC_MUL;
+
+ default:
+ return STAP_OPERAND_PREC_NONE;
+ }
+}
+
+/* Given S, read the operator in it and fills the OP pointer with its code.
+ Return 1 on success, zero if the operator was not recognized. */
+
+static int
+stap_get_opcode (const char **s, enum exp_opcode *op)
+{
+ const char c = **s;
+ int ret = 1;
+
+ *s += 1;
+
+ switch (c)
+ {
+ case '*':
+ *op = BINOP_MUL;
+ break;
+
+ case '/':
+ *op = BINOP_DIV;
+ break;
+
+ case '%':
+ *op = BINOP_REM;
+ break;
+
+ case '<':
+ *op = BINOP_LESS;
+ if (**s == '<')
+ {
+ *s += 1;
+ *op = BINOP_LSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_LEQ;
+ }
+ else if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_NOTEQUAL;
+ }
+ break;
+
+ case '>':
+ *op = BINOP_GTR;
+ if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_RSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_GEQ;
+ }
+ break;
+
+ case '|':
+ *op = BINOP_BITWISE_IOR;
+ if (**s == '|')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_OR;
+ }
+ break;
+
+ case '&':
+ *op = BINOP_BITWISE_AND;
+ if (**s == '&')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_AND;
+ }
+ break;
+
+ case '^':
+ *op = BINOP_BITWISE_XOR;
+ break;
+
+ case '!':
+ *op = UNOP_LOGICAL_NOT;
+ break;
+
+ case '+':
+ *op = BINOP_ADD;
+ break;
+
+ case '-':
+ *op = BINOP_SUB;
+ break;
+
+ case '=':
+ if (**s != '=')
+ {
+ ret = 0;
+ break;
+ }
+ *op = BINOP_EQUAL;
+ break;
+
+ default:
+ /* We didn't find any operator. */
+ *s -= 1;
+ return 0;
+ }
+
+ return ret;
+}
+
+/* Given the bitness of the argument, represented by B, return the
+ corresponding `struct type *'. */
+
+static struct type *
+stap_get_expected_argument_type (struct gdbarch *gdbarch,
+ enum stap_arg_bitness b)
+{
+ switch (b)
+ {
+ case STAP_ARG_BITNESS_UNDEFINED:
+ if (gdbarch_addr_bit (gdbarch) == 32)
+ return builtin_type (gdbarch)->builtin_uint32;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+
+ case STAP_ARG_BITNESS_32BIT_SIGNED:
+ return builtin_type (gdbarch)->builtin_int32;
+
+ case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+ return builtin_type (gdbarch)->builtin_uint32;
+
+ case STAP_ARG_BITNESS_64BIT_SIGNED:
+ return builtin_type (gdbarch)->builtin_int64;
+
+ case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+ return builtin_type (gdbarch)->builtin_uint64;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Undefined bitness for probe."));
+ break;
+ }
+}
+
+/* Function responsible for parsing a register operand according to
+ SystemTap parlance. Assuming:
+
+ RP = register prefix
+ RS = register suffix
+ RIP = register indirection prefix
+ RIS = register indirection suffix
+
+ Then a register operand can be:
+
+ [RIP] [RP] REGISTER [RS] [RIS]
+
+ This function takes care of a register's indirection, displacement and
+ direct access. It also takes into consideration the fact that some
+ registers are named differently inside and outside GDB, e.g., PPC's
+ general-purpose registers are represented by integers in the assembly
+ language (e.g., `15' is the 15th general-purpose register), but inside
+ GDB they have a prefix (the letter `r') appended. */
+
+static void
+stap_parse_register_operand (struct stap_parse_info *p)
+{
+ /* Simple flag to indicate whether we have seen a minus signal before
+ certain number. */
+ int got_minus = 0;
+
+ /* Flags to indicate whether this register access is being displaced and/or
+ indirected. */
+ int disp_p = 0, indirect_p = 0;
+ struct gdbarch *gdbarch = p->gdbarch;
+
+ /* Needed to generate the register name as a part of an expression. */
+ struct stoken str;
+
+ /* Variables used to extract the register name from the probe's
+ argument. */
+ const char *start;
+ char *regname;
+ int len;
+
+ /* Prefixes for the parser. */
+ const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
+ const char *reg_ind_prefix
+ = gdbarch_stap_register_indirection_prefix (gdbarch);
+ const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
+ int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
+ int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
+ int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0;
+
+ /* Suffixes for the parser. */
+ const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
+ const char *reg_ind_suffix
+ = gdbarch_stap_register_indirection_suffix (gdbarch);
+ const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
+ int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
+ int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
+ int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0;
+
+ /* Checking for a displacement argument. */
+ if (*p->arg == '+')
+ {
+ /* If it's a plus sign, we don't need to do anything, just advance the
+ pointer. */
+ ++p->arg;
+ }
+
+ if (*p->arg == '-')
+ {
+ got_minus = 1;
+ ++p->arg;
+ }
+
+ if (isdigit (*p->arg))
+ {
+ /* The value of the displacement. */
+ long displacement;
+
+ disp_p = 1;
+ displacement = strtol (p->arg, (char **) &p->arg, 10);
+
+ /* Generating the expression for the displacement. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacement);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ /* Getting rid of register indirection prefix. */
+ if (reg_ind_prefix
+ && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0)
+ {
+ indirect_p = 1;
+ p->arg += reg_ind_prefix_len;
+ }
+
+ if (disp_p && !indirect_p)
+ error (_("Invalid register displacement syntax on expression `%s'."),
+ p->saved_arg);
+
+ /* Getting rid of register prefix. */
+ if (reg_prefix && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
+ p->arg += reg_prefix_len;
+
+ /* Now we should have only the register name. Let's extract it and get
+ the associated number. */
+ start = p->arg;
+
+ /* We assume the register name is composed by letters and numbers. */
+ while (isalnum (*p->arg))
+ ++p->arg;
+
+ len = p->arg - start;
+
+ regname = alloca (len + gdb_reg_prefix_len + gdb_reg_suffix_len + 1);
+ regname[0] = '\0';
+
+ /* We only add the GDB's register prefix/suffix if we are dealing with
+ a numeric register. */
+ if (gdb_reg_prefix && isdigit (*start))
+ {
+ strncpy (regname, gdb_reg_prefix, gdb_reg_prefix_len);
+ strncpy (regname + gdb_reg_prefix_len, start, len);
+
+ if (gdb_reg_suffix)
+ strncpy (regname + gdb_reg_prefix_len + len,
+ gdb_reg_suffix, gdb_reg_suffix_len);
+
+ len += gdb_reg_prefix_len + gdb_reg_suffix_len;
+ }
+ else
+ strncpy (regname, start, len);
+
+ regname[len] = '\0';
+
+ /* Is this a valid register name? */
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (indirect_p)
+ {
+ if (disp_p)
+ write_exp_elt_opcode (BINOP_ADD);
+
+ /* Casting to the expected type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+ }
+
+ /* Getting rid of the register name suffix. */
+ if (reg_suffix)
+ {
+ if (strncmp (p->arg, reg_suffix, reg_suffix_len) != 0)
+ error (_("Missing register name suffix `%s' on expression `%s'."),
+ reg_suffix, p->saved_arg);
+
+ p->arg += reg_suffix_len;
+ }
+
+ /* Getting rid of the register indirection suffix. */
+ if (indirect_p && reg_ind_suffix)
+ {
+ if (strncmp (p->arg, reg_ind_suffix, reg_ind_suffix_len) != 0)
+ error (_("Missing indirection suffix `%s' on expression `%s'."),
+ reg_ind_suffix, p->saved_arg);
+
+ p->arg += reg_ind_suffix_len;
+ }
+}
+
+/* This function is responsible for parsing a single operand.
+
+ A single operand can be:
+
+ - an unary operation (e.g., `-5', `~2', or even with subexpressions
+ like `-(2 + 1)')
+ - a register displacement, which will be treated as a register
+ operand (e.g., `-4(%eax)' on x86)
+ - a numeric constant, or
+ - a register operand (see function `stap_parse_register_operand')
+
+ The function also calls special-handling functions to deal with
+ unrecognized operands, allowing arch-specific parsers to be
+ created. */
+
+static void
+stap_parse_single_operand (struct stap_parse_info *p)
+{
+ struct gdbarch *gdbarch = p->gdbarch;
+
+ /* Prefixes for the parser. */
+ const char *const_prefix = gdbarch_stap_integer_prefix (gdbarch);
+ const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
+ const char *reg_ind_prefix
+ = gdbarch_stap_register_indirection_prefix (gdbarch);
+ int const_prefix_len = const_prefix ? strlen (const_prefix) : 0;
+ int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
+ int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
+
+ /* Suffixes for the parser. */
+ const char *const_suffix = gdbarch_stap_integer_suffix (gdbarch);
+ const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
+ const char *reg_ind_suffix
+ = gdbarch_stap_register_indirection_suffix (gdbarch);
+ int const_suffix_len = const_suffix ? strlen (const_suffix) : 0;
+ int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
+ int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
+
+ /* We first try to parse this token as a "special token". */
+ if (gdbarch_stap_parse_special_token_p (gdbarch))
+ {
+ int ret = gdbarch_stap_parse_special_token (gdbarch, p);
+
+ if (ret)
+ {
+ /* If the return value of the above function is not zero,
+ it means it successfully parsed the special token.
+
+ If it is NULL, we try to parse it using our method. */
+ return;
+ }
+ }
+
+ if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+')
+ {
+ char c = *p->arg;
+ int number;
+
+ /* We use this variable to do a lookahead. */
+ const char *tmp = p->arg;
+
+ ++tmp;
+
+ /* This is an unary operation. Here is a list of allowed tokens
+ here:
+
+ - numeric literal;
+ - number (from register displacement)
+ - subexpression (beginning with `(')
+
+ We handle the register displacement here, and the other cases
+ recursively. */
+ if (p->inside_paren_p)
+ tmp = skip_spaces_const (tmp);
+
+ if (isdigit (*tmp))
+ number = strtol (tmp, (char **) &tmp, 10);
+
+ if (!reg_ind_prefix
+ || strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
+ {
+ /* This is not a displacement. We skip the operator, and deal
+ with it later. */
+ ++p->arg;
+ stap_parse_argument_conditionally (p);
+ if (c == '-')
+ write_exp_elt_opcode (UNOP_NEG);
+ else if (c == '~')
+ write_exp_elt_opcode (UNOP_COMPLEMENT);
+ }
+ else
+ {
+ /* If we are here, it means it is a displacement. The only
+ operations allowed here are `-' and `+'. */
+ if (c == '~')
+ error (_("Invalid operator `%c' for register displacement "
+ "on expression `%s'."), c, p->saved_arg);
+
+ stap_parse_register_operand (p);
+ }
+ }
+ else if (isdigit (*p->arg))
+ {
+ /* A temporary variable, needed for lookahead. */
+ const char *tmp = p->arg;
+ long number;
+
+ /* We can be dealing with a numeric constant (if `const_prefix' is
+ NULL), or with a register displacement. */
+ number = strtol (tmp, (char **) &tmp, 10);
+
+ if (p->inside_paren_p)
+ tmp = skip_spaces_const (tmp);
+ if (!const_prefix && reg_ind_prefix
+ && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
+ {
+ /* We are dealing with a numeric constant. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (number);
+ write_exp_elt_opcode (OP_LONG);
+
+ p->arg = tmp;
+
+ if (const_suffix)
+ {
+ if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
+ p->arg += const_suffix_len;
+ else
+ error (_("Invalid constant suffix on expression `%s'."),
+ p->saved_arg);
+ }
+ }
+ else if (reg_ind_prefix
+ && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) == 0)
+ stap_parse_register_operand (p);
+ else
+ error (_("Unknown numeric token on expression `%s'."),
+ p->saved_arg);
+ }
+ else if (const_prefix
+ && strncmp (p->arg, const_prefix, const_prefix_len) == 0)
+ {
+ /* We are dealing with a numeric constant. */
+ long number;
+
+ p->arg += const_prefix_len;
+ number = strtol (p->arg, (char **) &p->arg, 10);
+
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (number);
+ write_exp_elt_opcode (OP_LONG);
+
+ if (const_suffix)
+ {
+ if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
+ p->arg += const_suffix_len;
+ else
+ error (_("Invalid constant suffix on expression `%s'."),
+ p->saved_arg);
+ }
+ }
+ else if ((reg_prefix
+ && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
+ || (reg_ind_prefix
+ && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0))
+ stap_parse_register_operand (p);
+ else
+ error (_("Operator `%c' not recognized on expression `%s'."),
+ *p->arg, p->saved_arg);
+}
+
+/* This function parses an argument conditionally, based on single or
+ non-single operands. A non-single operand would be a parenthesized
+ expression (e.g., `(2 + 1)'), and a single operand is anything that
+ starts with `-', `~', `+' (i.e., unary operators), a digit, or
+ something recognized by `gdbarch_stap_is_single_operand'. */
+
+static void
+stap_parse_argument_conditionally (struct stap_parse_info *p)
+{
+ if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */
+ || isdigit (*p->arg)
+ || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
+ stap_parse_single_operand (p);
+ else if (*p->arg == '(')
+ {
+ /* We are dealing with a parenthesized operand. It means we
+ have to parse it as it was a separate expression, without
+ left-side or precedence. */
+ ++p->arg;
+ p->arg = skip_spaces_const (p->arg);
+ ++p->inside_paren_p;
+
+ stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
+
+ --p->inside_paren_p;
+ if (*p->arg != ')')
+ error (_("Missign close-paren on expression `%s'."),
+ p->saved_arg);
+
+ ++p->arg;
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+ }
+ else
+ error (_("Cannot parse expression `%s'."), p->saved_arg);
+}
+
+/* Helper function for `stap_parse_argument'. Please, see its comments to
+ better understand what this function does. */
+
+static void
+stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
+ enum stap_operand_prec prec)
+{
+ /* This is an operator-precedence parser.
+
+ We work with left- and right-sides of expressions, and
+ parse them depending on the precedence of the operators
+ we find. */
+
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+
+ if (!has_lhs)
+ {
+ /* We were called without a left-side, either because this is the
+ first call, or because we were called to parse a parenthesized
+ expression. It doesn't really matter; we have to parse the
+ left-side in order to continue the process. */
+ stap_parse_argument_conditionally (p);
+ }
+
+ /* Start to parse the right-side, and to "join" left and right sides
+ depending on the operation specified.
+
+ This loop shall continue until we run out of characters in the input,
+ or until we find a close-parenthesis, which means that we've reached
+ the end of a sub-expression. */
+ while (p->arg && *p->arg && *p->arg != ')' && !isspace (*p->arg))
+ {
+ const char *tmp_exp_buf;
+ enum exp_opcode opcode;
+ enum stap_operand_prec cur_prec;
+
+ if (!stap_is_operator (*p->arg))
+ error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
+ p->saved_arg);
+
+ /* We have to save the current value of the expression buffer because
+ the `stap_get_opcode' modifies it in order to get the current
+ operator. If this operator's precedence is lower than PREC, we
+ should return and not advance the expression buffer pointer. */
+ tmp_exp_buf = p->arg;
+ stap_get_opcode (&tmp_exp_buf, &opcode);
+
+ cur_prec = stap_get_operator_prec (opcode);
+ if (cur_prec < prec)
+ {
+ /* If the precedence of the operator that we are seeing now is
+ lower than the precedence of the first operator seen before
+ this parsing process began, it means we should stop parsing
+ and return. */
+ break;
+ }
+
+ p->arg = tmp_exp_buf;
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+
+ /* Parse the right-side of the expression. */
+ stap_parse_argument_conditionally (p);
+
+ /* While we still have operators, try to parse another
+ right-side, but using the current right-side as a left-side. */
+ while (*p->arg && stap_is_operator (*p->arg))
+ {
+ enum exp_opcode lookahead_opcode;
+ enum stap_operand_prec lookahead_prec;
+
+ /* Saving the current expression buffer position. The explanation
+ is the same as above. */
+ tmp_exp_buf = p->arg;
+ stap_get_opcode (&tmp_exp_buf, &lookahead_opcode);
+ lookahead_prec = stap_get_operator_prec (lookahead_opcode);
+
+ if (lookahead_prec <= prec)
+ {
+ /* If we are dealing with an operator whose precedence is lower
+ than the first one, just abandon the attempt. */
+ break;
+ }
+
+ /* Parse the right-side of the expression, but since we already
+ have a left-side at this point, set `has_lhs' to 1. */
+ stap_parse_argument_1 (p, 1, lookahead_prec);
+ }
+
+ write_exp_elt_opcode (opcode);
+ }
+}
+
+/* Parse a probe's argument.
+
+ Assuming that:
+
+ LP = literal integer prefix
+ LS = literal integer suffix
+
+ RP = register prefix
+ RS = register suffix
+
+ RIP = register indirection prefix
+ RIS = register indirection suffix
+
+ This routine assumes that arguments' tokens are of the form:
+
+ - [LP] NUMBER [LS]
+ - [RP] REGISTER [RS]
+ - [RIP] [RP] REGISTER [RS] [RIS]
+ - If we find a number without LP, we try to parse it as a literal integer
+ constant (if LP == NULL), or as a register displacement.
+ - We count parenthesis, and only skip whitespaces if we are inside them.
+ - If we find an operator, we skip it.
+
+ This function can also call a special function that will try to match
+ unknown tokens. It will return 1 if the argument has been parsed
+ successfully, or zero otherwise. */
+
+static struct expression *
+stap_parse_argument (const char **arg, struct type *atype,
+ struct gdbarch *gdbarch)
+{
+ struct stap_parse_info p;
+ volatile struct gdb_exception e;
+ struct cleanup *back_to;
+
+ /* We need to initialize the expression buffer, in order to begin
+ our parsing efforts. The language here does not matter, since we
+ are using our own parser. */
+ initialize_expout (10, current_language, gdbarch);
+ back_to = make_cleanup (free_current_contents, &expout);
+
+ p.saved_arg = *arg;
+ p.arg = *arg;
+ p.arg_type = atype;
+ p.gdbarch = gdbarch;
+ p.inside_paren_p = 0;
+
+ stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
+
+ discard_cleanups (back_to);
+
+ gdb_assert (p.inside_paren_p == 0);
+
+ /* Casting the final expression to the appropriate type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (atype);
+ write_exp_elt_opcode (UNOP_CAST);
+
+ reallocate_expout ();
+
+ p.arg = skip_spaces_const (p.arg);
+ *arg = p.arg;
+
+ return expout;
+}
+
+/* Function which parses an argument string from PROBE, correctly splitting
+ the arguments and storing their information in properly ways.
+
+ Consider the following argument string (x86 syntax):
+
+ `4@%eax 4@$10'
+
+ We have two arguments, `%eax' and `$10', both with 32-bit unsigned bitness.
+ This function basically handles them, properly filling some structures with
+ this information. */
+
+static void
+stap_parse_probe_arguments (struct stap_probe *probe, struct objfile *objfile)
+{
+ const char *cur;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ gdb_assert (!probe->args_parsed);
+ cur = probe->args_u.text;
+ probe->args_parsed = 1;
+ probe->args_u.vec = NULL;
+
+ if (!cur || !*cur || *cur == ':')
+ return;
+
+ while (*cur)
+ {
+ struct stap_probe_arg arg;
+ enum stap_arg_bitness b;
+ int got_minus = 0;
+ struct expression *expr;
+
+ memset (&arg, 0, sizeof (arg));
+
+ /* We expect to find something like:
+
+ N@OP
+
+ Where `N' can be [+,-][4,8]. This is not mandatory, so
+ we check it here. If we don't find it, go to the next
+ state. */
+ if ((*cur == '-' && cur[1] && cur[2] != '@')
+ && cur[1] != '@')
+ arg.bitness = STAP_ARG_BITNESS_UNDEFINED;
+ else
+ {
+ if (*cur == '-')
+ {
+ /* Discard the `-'. */
+ ++cur;
+ got_minus = 1;
+ }
+
+ if (*cur == '4')
+ b = (got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
+ : STAP_ARG_BITNESS_32BIT_UNSIGNED);
+ else if (*cur == '8')
+ b = (got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
+ : STAP_ARG_BITNESS_64BIT_UNSIGNED);
+ else
+ {
+ /* We have an error, because we don't expect anything
+ except 4 and 8. */
+ complaint (&symfile_complaints,
+ _("unrecognized bitness `%c' for probe `%s'"),
+ *cur, probe->p.name);
+ return;
+ }
+
+ arg.bitness = b;
+ arg.atype = stap_get_expected_argument_type (gdbarch, b);
+
+ /* Discard the number and the `@' sign. */
+ cur += 2;
+ }
+
+ expr = stap_parse_argument (&cur, arg.atype, gdbarch);
+
+ if (stap_expression_debug)
+ dump_raw_expression (expr, gdb_stdlog,
+ "before conversion to prefix form");
+
+ prefixify_expression (expr);
+
+ if (stap_expression_debug)
+ dump_prefix_expression (expr, gdb_stdlog);
+
+ arg.aexpr = expr;
+
+ /* Start it over again. */
+ cur = skip_spaces_const (cur);
+
+ VEC_safe_push (stap_probe_arg_s, probe->args_u.vec, &arg);
+ }
+}
+
+/* Given PROBE, returns the number of arguments present in that probe's
+ argument string. */
+
+static unsigned
+stap_get_probe_argument_count (struct probe *probe_generic,
+ struct objfile *objfile)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ if (!probe->args_parsed)
+ stap_parse_probe_arguments (probe, objfile);
+
+ gdb_assert (probe->args_parsed);
+ return VEC_length (stap_probe_arg_s, probe->args_u.vec);
+}
+
+/* Return 1 if OP is a valid operator inside a probe argument, or zero
+ otherwise. */
+
+static int
+stap_is_operator (char op)
+{
+ return (op == '+' || op == '-' || op == '*' || op == '/'
+ || op == '>' || op == '<' || op == '!' || op == '^'
+ || op == '|' || op == '&' || op == '%' || op == '=');
+}
+
+static struct stap_probe_arg *
+stap_get_arg (struct stap_probe *probe, struct objfile *objfile, unsigned n)
+{
+ if (!probe->args_parsed)
+ stap_parse_probe_arguments (probe, objfile);
+
+ return VEC_index (stap_probe_arg_s, probe->args_u.vec, n);
+}
+
+/* Evaluate the probe's argument N (indexed from 0), returning a value
+ corresponding to it. Assertion is thrown if N does not exist. */
+
+static struct value *
+stap_evaluate_probe_argument (struct probe *probe_generic,
+ struct objfile *objfile, unsigned n)
+{
+ struct stap_probe *stap_probe = (struct stap_probe *) probe_generic;
+ struct stap_probe_arg *arg;
+ int pos = 0;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ arg = stap_get_arg (stap_probe, objfile, n);
+ return evaluate_subexp_standard (arg->atype, arg->aexpr, &pos, EVAL_NORMAL);
+}
+
+/* Compile the probe's argument N (indexed from 0) to agent expression.
+ Assertion is thrown if N does not exist. */
+
+static void
+stap_compile_to_ax (struct probe *probe_generic, struct objfile *objfile,
+ struct agent_expr *expr, struct axs_value *value,
+ unsigned n)
+{
+ struct stap_probe *stap_probe = (struct stap_probe *) probe_generic;
+ struct stap_probe_arg *arg;
+ union exp_element *pc;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ arg = stap_get_arg (stap_probe, objfile, n);
+
+ pc = arg->aexpr->elts;
+ gen_expr (arg->aexpr, &pc, expr, value);
+
+ require_rvalue (expr, value);
+ value->type = arg->atype;
+}
+
+/* Destroy (free) the data related to PROBE. PROBE memory itself is not feed
+ as it is allocated from OBJFILE_OBSTACK. */
+
+static void
+stap_probe_destroy (struct probe *probe_generic)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ if (probe->args_parsed)
+ {
+ struct stap_probe_arg *arg;
+ int ix;
+
+ for (ix = 0; VEC_iterate (stap_probe_arg_s, probe->args_u.vec, ix, arg);
+ ++ix)
+ xfree (arg->aexpr);
+ VEC_free (stap_probe_arg_s, probe->args_u.vec);
+ }
+}
+
+\f
+
+/* This is called to compute the value of one of the $_probe_arg*
+ convenience variables. */
+
+static struct value *
+compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
+ void *data)
+{
+ struct frame_info *frame = get_selected_frame (_("No frame selected"));
+ CORE_ADDR pc = get_frame_pc (frame);
+ int sel = (int) (uintptr_t) data;
+ struct objfile *objfile;
+ struct probe *pc_probe;
+ unsigned n_args;
+
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_args
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ 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 objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ pc_probe,
+ sel);
+}
+
+/* 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 objfile *objfile;
+ struct probe *pc_probe;
+ int n_probes;
+
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ if (sel == -1)
+ {
+ value->kind = axs_rvalue;
+ value->type = builtin_type (expr->gdbarch)->builtin_int;
+ ax_const_l (expr, n_probes);
+ return;
+ }
+
+ gdb_assert (sel >= 0);
+ if (sel >= n_probes)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_probes);
+
+ objfile->sf->sym_probe_fns->sym_compile_to_ax (objfile, pc_probe,
+ expr, value, sel);
+}
+
+\f
+
+/* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's
+ address. SET is zero if the semaphore should be cleared, or one
+ if it should be set. This is a helper function for `stap_semaphore_down'
+ and `stap_semaphore_up'. */
+
+static void
+stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
+{
+ gdb_byte bytes[sizeof (LONGEST)];
+ /* The ABI specifies "unsigned short". */
+ struct type *type = builtin_type (gdbarch)->builtin_unsigned_short;
+ ULONGEST value;
+
+ if (address == 0)
+ return;
+
+ /* Swallow errors. */
+ if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
+ {
+ warning (_("Could not read the value of a SystemTap semaphore."));
+ return;
+ }
+
+ value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
+ gdbarch_byte_order (gdbarch));
+ /* Note that we explicitly don't worry about overflow or
+ underflow. */
+ if (set)
+ ++value;
+ else
+ --value;
+
+ store_unsigned_integer (bytes, TYPE_LENGTH (type),
+ gdbarch_byte_order (gdbarch), value);
+
+ if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0)
+ warning (_("Could not write the value of a SystemTap semaphore."));
+}
+
+/* Set a SystemTap semaphore. SEM is the semaphore's address. Semaphores
+ act as reference counters, so calls to this function must be paired with
+ calls to `stap_semaphore_down'.
+
+ This function and `stap_semaphore_down' race with another tool changing
+ the probes, but that is too rare to care. */
+
+static void
+stap_set_semaphore (struct probe *probe_generic, struct gdbarch *gdbarch)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ stap_modify_semaphore (probe->sem_addr, 1, gdbarch);
+}
+
+/* Clear a SystemTap semaphore. SEM is the semaphore's address. */
+
+static void
+stap_clear_semaphore (struct probe *probe_generic, struct gdbarch *gdbarch)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ stap_modify_semaphore (probe->sem_addr, 0, gdbarch);
+}
+
+/* Implementation of `$_probe_arg*' set of variables. */
+
+static const struct internalvar_funcs probe_funcs =
+{
+ compute_probe_arg,
+ compile_probe_arg,
+ NULL
+};
+
+/* Helper function that parses the information contained in a
+ SystemTap's probe. Basically, the information consists in:
+
+ - Probe's PC address;
+ - Link-time section address of `.stapsdt.base' section;
+ - Link-time address of the semaphore variable, or ZERO if the
+ probe doesn't have an associated semaphore;
+ - Probe's provider name;
+ - Probe's name;
+ - Probe's argument format
+
+ This function returns 1 if the handling was successful, and zero
+ otherwise. */
+
+static void
+handle_stap_probe (struct objfile *objfile, struct sdt_note *el,
+ VEC (probe_p) **probesp, CORE_ADDR base)
+{
+ bfd *abfd = objfile->obfd;
+ int size = bfd_get_arch_size (abfd) / 8;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ CORE_ADDR base_ref;
+ const char *probe_args = NULL;
+ struct stap_probe *ret;
+
+ ret = obstack_alloc (&objfile->objfile_obstack, sizeof (*ret));
+ ret->p.pops = &stap_probe_ops;
+
+ /* Provider and the name of the probe. */
+ ret->p.provider = &el->data[3 * size];
+ ret->p.name = memchr (ret->p.provider, '\0',
+ (char *) el->data + el->size - ret->p.provider);
+ /* Making sure there is a name. */
+ if (!ret->p.name)
+ {
+ complaint (&symfile_complaints, _("corrupt probe name when "
+ "reading `%s'"), objfile->name);
+
+ /* There is no way to use a probe without a name or a provider, so
+ returning zero here makes sense. */
+ return;
+ }
+ else
+ ++ret->p.name;
+
+ /* Retrieving the probe's address. */
+ ret->p.address = extract_typed_address (&el->data[0], ptr_type);
+
+ /* Link-time sh_addr of `.stapsdt.base' section. */
+ base_ref = extract_typed_address (&el->data[size], ptr_type);
+
+ /* Semaphore address. */
+ ret->sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
+
+ ret->p.address += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))
+ + base - base_ref);
+ if (ret->sem_addr)
+ ret->sem_addr += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_DATA (objfile))
+ + base - base_ref);
+
+ /* Arguments. We can only extract the argument format if there is a valid
+ name for this probe. */
+ probe_args = memchr (ret->p.name, '\0',
+ (char *) el->data + el->size - ret->p.name);
+
+ if (probe_args != NULL)
+ ++probe_args;
+
+ if (probe_args == NULL || (memchr (probe_args, '\0',
+ (char *) el->data + el->size - ret->p.name)
+ != el->data + el->size - 1))
+ {
+ complaint (&symfile_complaints, _("corrupt probe argument when "
+ "reading `%s'"), objfile->name);
+ /* If the argument string is NULL, it means some problem happened with
+ it. So we return 0. */
+ return;
+ }
+
+ ret->args_parsed = 0;
+ ret->args_u.text = (void *) probe_args;
+
+ /* Successfully created probe. */
+ VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
+}
+
+/* Helper function which tries to find the base address of the SystemTap
+ base section named STAP_BASE_SECTION_NAME. */
+
+static void
+get_stap_base_address_1 (bfd *abfd, asection *sect, void *obj)
+{
+ asection **ret = obj;
+
+ if ((sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
+ && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
+ *ret = sect;
+}
+
+/* Helper function which iterates over every section in the BFD file,
+ trying to find the base address of the SystemTap base section.
+ Returns 1 if found (setting BASE to the proper value), zero otherwise. */
+
+static int
+get_stap_base_address (bfd *obfd, bfd_vma *base)
+{
+ asection *ret = NULL;
+
+ bfd_map_over_sections (obfd, get_stap_base_address_1, (void *) &ret);
+
+ if (!ret)
+ {
+ complaint (&symfile_complaints, _("could not obtain base address for "
+ "SystemTap section on objfile `%s'."),
+ obfd->filename);
+ return 0;
+ }
+
+ if (base)
+ *base = ret->vma;
+
+ return 1;
+}
+
+/* Helper function for `elf_get_probes', which gathers information about all
+ SystemTap probes from OBJFILE. */
+
+static void
+stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
+{
+ /* If we are here, then this is the first time we are parsing the
+ SystemTap probe's information. We basically have to count how many
+ probes the objfile has, and then fill in the necessary information
+ for each one. */
+ bfd *obfd = objfile->obfd;
+ bfd_vma base;
+ struct sdt_note *iter;
+ unsigned save_probesp_len = VEC_length (probe_p, *probesp);
+
+ if (!elf_tdata (obfd)->sdt_note_head)
+ {
+ /* There isn't any probe here. */
+ return;
+ }
+
+ if (!get_stap_base_address (obfd, &base))
+ {
+ /* There was an error finding the base address for the section.
+ Just return NULL. */
+ return;
+ }
+
+ /* Parsing each probe's information. */
+ for (iter = elf_tdata (obfd)->sdt_note_head; iter; iter = iter->next)
+ {
+ /* We first have to handle all the information about the
+ probe which is present in the section. */
+ handle_stap_probe (objfile, iter, probesp, base);
+ }
+
+ if (save_probesp_len == VEC_length (probe_p, *probesp))
+ {
+ /* If we are here, it means we have failed to parse every known
+ probe. */
+ complaint (&symfile_complaints, _("could not parse SystemTap probe(s) "
+ "from inferior"));
+ return;
+ }
+}
+
+static void
+stap_relocate (struct probe *probe_generic, CORE_ADDR delta)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ probe->p.address += delta;
+ if (probe->sem_addr)
+ probe->sem_addr += delta;
+}
+
+static int
+stap_probe_is_linespec (const char **linespecp)
+{
+ static const char *const keywords[] = { "-pstap", "-probe-stap", NULL };
+
+ return probe_is_linespec_by_keyword (linespecp, keywords);
+}
+
+static void
+stap_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
+{
+ info_probe_column_s stap_probe_column;
+
+ stap_probe_column.field_name = "semaphore";
+ stap_probe_column.print_name = _("Semaphore");
+
+ VEC_safe_push (info_probe_column_s, *heads, &stap_probe_column);
+}
+
+static void
+stap_gen_info_probes_table_values (struct probe *probe_generic,
+ struct objfile *objfile,
+ VEC (const_char_ptr) **ret)
+{
+ struct stap_probe *probe = (struct stap_probe *) probe_generic;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ const char *val = NULL;
+
+ gdb_assert (probe_generic->pops == &stap_probe_ops);
+
+ if (probe->sem_addr)
+ val = print_core_address (gdbarch, probe->sem_addr);
+
+ VEC_safe_push (const_char_ptr, *ret, val);
+}
+
+/* SystemTap probe_ops. */
+
+static const struct probe_ops stap_probe_ops =
+{
+ stap_probe_is_linespec,
+ stap_get_probes,
+ stap_relocate,
+ stap_get_probe_argument_count,
+ stap_evaluate_probe_argument,
+ stap_compile_to_ax,
+ stap_set_semaphore,
+ stap_clear_semaphore,
+ stap_probe_destroy,
+ stap_gen_info_probes_table_header,
+ stap_gen_info_probes_table_values,
+};
+
+/* Implementation of the `info probes stap' command. */
+
+static void
+info_probes_stap_command (char *arg, int from_tty)
+{
+ info_probes_for_ops (arg, from_tty, &stap_probe_ops);
+}
+
+void _initialize_stap_probe (void);
+
+void
+_initialize_stap_probe (void)
+{
+ VEC_safe_push (probe_ops_cp, all_probe_ops, &stap_probe_ops);
+
+ add_setshow_zinteger_cmd ("stap-expression", class_maintenance,
+ &stap_expression_debug,
+ _("Set SystemTap expression debugging."),
+ _("Show SystemTap expression debugging."),
+ _("When non-zero, the internal representation "
+ "of SystemTap expressions will be printed."),
+ NULL,
+ show_stapexpressiondebug,
+ &setdebuglist, &showdebuglist);
+
+ 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 ("stap", class_info, info_probes_stap_command,
+ _("\
+Show information about SystemTap static probes.\n\
+Usage: info probes stap [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 ());
+
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..0e9df06
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,52 @@
+/* SystemTap 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/>. */
+
+#if !defined (STAP_PROBE_H)
+#define STAP_PROBE_H 1
+
+#include "probe.h"
+
+/* Structure which holds information about the parsing process of one probe's
+ argument. */
+
+struct stap_parse_info
+{
+ /* The probe's argument in a string format. */
+ const char *arg;
+
+ /* A pointer to the full chain of arguments. This is useful for printing
+ error messages. The parser functions should not modify this argument
+ directly; instead, they should use the ARG pointer above. */
+ const char *saved_arg;
+
+ /* The expected argument type (bitness), as defined in the probe's
+ argument. For instance, if the argument begins with `-8@', it means
+ the bitness is 64-bit signed. In this case, ARG_TYPE would represent
+ the type `int64_t'. */
+ struct type *arg_type;
+
+ /* A pointer to the current gdbarch. */
+ struct gdbarch *gdbarch;
+
+ /* Greater than zero if we are inside a parenthesized expression. Useful
+ for knowing when to skip spaces or not. */
+ int inside_paren_p;
+};
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 7024ace..bf3f7a0 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -22,6 +22,7 @@
/* This file requires that you first include "bfd.h". */
#include "symtab.h"
+#include "gdb_vecs.h"
/* Opaque declarations. */
struct target_section;
@@ -29,6 +30,11 @@ struct objfile;
struct obj_section;
struct obstack;
struct block;
+struct probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
/* Comparison function for symbol look ups. */
@@ -297,6 +303,52 @@ struct quick_symbol_functions
int need_fullname);
};
+/* Structure of functions used for probe support. If one of these functions
+ is provided, all must be. */
+
+struct sym_probe_fns
+{
+ /* If non-NULL, return an array of probe objects.
+
+ The returned value does not have to be freed and it has lifetime of the
+ OBJFILE. */
+ VEC (probe_p) *(*sym_get_probes) (struct objfile *);
+
+ /* Return the number of arguments available to PROBE. PROBE will
+ have come from a call to this objfile's sym_get_probes method.
+ If you provide an implementation of sym_get_probes, you must
+ implement this method as well. */
+ unsigned (*sym_get_probe_argument_count) (struct objfile *objfile,
+ struct probe *probe);
+
+ /* Evaluate the Nth argument available to PROBE. PROBE will have
+ come from a call to this objfile's sym_get_probes method. N will
+ be between 0 and the number of arguments available to this probe.
+ FRAME is the frame in which the evaluation is done; the frame's
+ PC will match the address of the probe. If you provide an
+ implementation of sym_get_probes, you must implement this method
+ as well. */
+ struct value *(*sym_evaluate_probe_argument) (struct objfile *objfile,
+ struct probe *probe,
+ unsigned n);
+
+ /* Compile the Nth probe argument to an agent expression. PROBE
+ will have come from a call to this objfile's sym_get_probes
+ method. N will be between 0 and the number of arguments
+ available to this probe. EXPR and VALUE are the agent expression
+ that is being updated. */
+ void (*sym_compile_to_ax) (struct objfile *objfile,
+ struct probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ unsigned n);
+
+ /* Relocate the probe section of OBJFILE. */
+ void (*sym_relocate_probe) (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta);
+};
+
/* Structure to keep track of symbol reading functions for various
object file types. */
@@ -367,6 +419,10 @@ struct sym_fns
bfd_byte *(*sym_relocate) (struct objfile *, asection *sectp, bfd_byte *buf);
+ /* If non-NULL, this objfile has probe support, and all the probe
+ functions referred to here will be non-NULL. */
+ const struct sym_probe_fns *sym_probe_fns;
+
/* The "quick" (aka partial) symbol functions for this symbol
reader. */
const struct quick_symbol_functions *qf;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index af115cd..aa89fac 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -877,6 +877,7 @@ init_sal (struct symtab_and_line *sal)
sal->end = 0;
sal->explicit_pc = 0;
sal->explicit_line = 0;
+ sal->probe = NULL;
}
\f
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 6933c0c..61e7c0f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,7 @@ struct axs_value;
struct agent_expr;
struct program_space;
struct language_defn;
+struct probe;
/* Some of the structures in this file are space critical.
The space-critical structures are:
@@ -1042,6 +1043,9 @@ struct symtab_and_line
CORE_ADDR end;
int explicit_pc;
int explicit_line;
+
+ /* The probe associated with this symtab_and_line. */
+ struct probe *probe;
};
extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index c213374..e5b57e1 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -52,6 +52,7 @@
#include "memrange.h"
#include "exceptions.h"
#include "cli/cli-utils.h"
+#include "probe.h"
/* readline include files */
#include "readline/readline.h"
@@ -1717,6 +1718,7 @@ start_tracing (char *notes)
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
{
struct tracepoint *t = (struct tracepoint *) b;
+ struct bp_location *loc;
if (b->enable_state == bp_enabled)
any_enabled = 1;
@@ -1779,6 +1781,9 @@ start_tracing (char *notes)
}
t->number_on_target = b->number;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
}
VEC_free (breakpoint_p, tp_vec);
@@ -1851,9 +1856,34 @@ void
stop_tracing (char *note)
{
int ret;
+ VEC(breakpoint_p) *tp_vec = NULL;
+ int ix;
+ struct breakpoint *t;
target_trace_stop ();
+ tp_vec = all_tracepoints ();
+ for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+ {
+ struct bp_location *loc;
+
+ if ((t->type == bp_fast_tracepoint
+ ? !may_insert_fast_tracepoints
+ : !may_insert_tracepoints))
+ continue;
+
+ for (loc = t->loc; loc; loc = loc->next)
+ {
+ /* GDB can be totally absent in some disconnected trace scenarios,
+ but we don't really care if this semaphore goes out of sync.
+ That's why we are decrementing it here, but not taking care
+ in other places. */
+ loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
+ }
+ }
+
+ VEC_free (breakpoint_p, tp_vec);
+
if (!note)
note = trace_stop_notes;
ret = target_set_trace_notes (NULL, NULL, note);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 1a1b5de..2d2e0bb 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3136,6 +3136,7 @@ static const struct sym_fns xcoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
aix_process_linenos,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
--
1.7.7.6
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 3/4 v3] Use longjmp and exception probes when available
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 1/4 v3] Refactor internal variable mechanism Sergio Durigan Junior
@ 2012-04-23 4:59 ` Sergio Durigan Junior
2012-04-27 19:47 ` Tom Tromey
2012-04-23 4:59 ` [PATCH 2/4 v3] Implement support for static and SystemTap probes Sergio Durigan Junior
` (2 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-23 4:59 UTC (permalink / raw)
To: gdb-patches
Hi,
This patch also almost didn't change from the first version.
http://sourceware.org/ml/gdb-patches/2012-03/msg00356.html
OK to check-in?
2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* breakpoint.c (struct breakpoint_objfile_data)
<longjmp_searched>,<longjmp_probes>,<exception_searched>,
<exception_probes>: New fields.
(free_breakpoint_probes): New function.
(create_longjmp_master_breakpoint): Prefer SystemTap probe over
`_Unwind_DebugHook'.
(create_exception_master_breakpoint): Likewise.
(_initialize_breakpoint): Registering cleanup for SystemTap probes.
* infrun.c: Including necessary header files for handling SystemTap
probes.
(handle_inferior_event): Handling longjmp breakpoint and exceptions
via SystemTap probes.
(check_exception_resume): Remove `func' argument. Handle exception
unwinding breakpoint set via a SystemTap probe.
(insert_exception_resume_from_probe): New function.
---
gdb/breakpoint.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/infrun.c | 77 +++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 152 insertions(+), 11 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ce0ee62..1d719e4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2733,11 +2733,23 @@ struct breakpoint_objfile_data
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ /* True if we have looked for longjmp probes. */
+ int longjmp_searched;
+
+ /* SystemTap probe points for longjmp (if any). */
+ VEC (probe_p) *longjmp_probes;
+
/* Minimal symbol for "std::terminate()" (if any). */
struct minimal_symbol *terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
struct minimal_symbol *exception_msym;
+
+ /* True if we have looked for exception probes. */
+ int exception_searched;
+
+ /* SystemTap probe points for unwinding (if any). */
+ VEC (probe_p) *exception_probes;
};
static const struct objfile_data *breakpoint_objfile_key;
@@ -2774,6 +2786,15 @@ get_breakpoint_objfile_data (struct objfile *objfile)
}
static void
+free_breakpoint_probes (struct objfile *obj, void *data)
+{
+ struct breakpoint_objfile_data *bp_objfile_data = data;
+
+ VEC_free (probe_p, bp_objfile_data->longjmp_probes);
+ VEC_free (probe_p, bp_objfile_data->exception_probes);
+}
+
+static void
create_overlay_event_breakpoint (void)
{
struct objfile *objfile;
@@ -2850,6 +2871,37 @@ create_longjmp_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ if (!bp_objfile_data->longjmp_searched)
+ {
+ bp_objfile_data->longjmp_probes
+ = find_probes_in_objfile (objfile, "libc", "longjmp");
+ bp_objfile_data->longjmp_searched = 1;
+ }
+
+ if (bp_objfile_data->longjmp_probes != NULL)
+ {
+ int i;
+ struct probe *probe;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->longjmp_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_longjmp_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libc:longjmp");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
@@ -2960,6 +3012,40 @@ create_exception_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ /* We prefer the SystemTap probe point if it exists. */
+ if (!bp_objfile_data->exception_searched)
+ {
+ bp_objfile_data->exception_probes
+ = find_probes_in_objfile (objfile, "libgcc", "unwind");
+ bp_objfile_data->exception_searched = 1;
+ }
+
+ if (bp_objfile_data->exception_probes != NULL)
+ {
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ int i;
+ struct probe *probe;
+
+ for (i = 0;
+ VEC_iterate (probe_p,
+ bp_objfile_data->exception_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_exception_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
+ /* Otherwise, try the hook function. */
+
if (msym_not_found_p (bp_objfile_data->exception_msym))
continue;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c8a697a..e779c2a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -55,6 +55,8 @@
#include "continuations.h"
#include "interps.h"
#include "skip.h"
+#include "probe.h"
+#include "objfiles.h"
/* Prototypes for local functions */
@@ -2402,7 +2404,7 @@ static void handle_step_into_function (struct gdbarch *gdbarch,
static void handle_step_into_function_backward (struct gdbarch *gdbarch,
struct execution_control_state *ecs);
static void check_exception_resume (struct execution_control_state *,
- struct frame_info *, struct symbol *);
+ struct frame_info *);
static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
@@ -4437,9 +4439,17 @@ process_event_stop_test:
if (what.is_longjmp)
{
- if (!gdbarch_get_longjmp_target_p (gdbarch)
- || !gdbarch_get_longjmp_target (gdbarch,
- frame, &jmp_buf_pc))
+ struct value *arg_value;
+
+ /* If we set the longjmp breakpoint via a SystemTap probe,
+ then use it to extract the arguments. The destination
+ PC is the third argument to the probe. */
+ arg_value = probe_safe_evaluate_at_pc (frame, 2);
+ if (arg_value)
+ jmp_buf_pc = value_as_address (arg_value);
+ else if (!gdbarch_get_longjmp_target_p (gdbarch)
+ || !gdbarch_get_longjmp_target (gdbarch,
+ frame, &jmp_buf_pc))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -4457,12 +4467,7 @@ process_event_stop_test:
insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
}
else
- {
- struct symbol *func = get_frame_function (frame);
-
- if (func)
- check_exception_resume (ecs, frame, func);
- }
+ check_exception_resume (ecs, frame);
keep_going (ecs);
return;
@@ -5549,15 +5554,65 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
}
}
+/* A helper for check_exception_resume that sets an
+ exception-breakpoint based on a SystemTap probe. */
+
+static void
+insert_exception_resume_from_probe (struct thread_info *tp,
+ const struct probe *probe,
+ struct objfile *objfile,
+ struct frame_info *frame)
+{
+ struct value *arg_value;
+ CORE_ADDR handler;
+ struct breakpoint *bp;
+
+ arg_value = probe_safe_evaluate_at_pc (frame, 1);
+ if (!arg_value)
+ return;
+
+ handler = value_as_address (arg_value);
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: exception resume at %s\n",
+ paddress (get_objfile_arch (objfile),
+ handler));
+
+ bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+ handler, bp_exception_resume);
+ bp->thread = tp->num;
+ inferior_thread ()->control.exception_resume_breakpoint = bp;
+}
+
/* This is called when an exception has been intercepted. Check to
see whether the exception's destination is of interest, and if so,
set an exception resume breakpoint there. */
static void
check_exception_resume (struct execution_control_state *ecs,
- struct frame_info *frame, struct symbol *func)
+ struct frame_info *frame)
{
volatile struct gdb_exception e;
+ struct objfile *objfile;
+ const struct probe *probe;
+ struct symbol *func;
+
+ /* First see if this exception unwinding breakpoint was set via a
+ SystemTap probe point. If so, the probe has two arguments: the
+ CFA and the HANDLER. We ignore the CFA, extract the handler, and
+ set a breakpoint there. */
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (probe)
+ {
+ insert_exception_resume_from_probe (ecs->event_thread, probe,
+ objfile, frame);
+ return;
+ }
+
+ func = get_frame_function (frame);
+ if (!func)
+ return;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
--
1.7.7.6
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/4 v3] Refactor internal variable mechanism
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
@ 2012-04-23 4:59 ` Sergio Durigan Junior
2012-04-27 15:40 ` Tom Tromey
2012-04-23 4:59 ` [PATCH 3/4 v3] Use longjmp and exception probes when available Sergio Durigan Junior
` (3 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-23 4:59 UTC (permalink / raw)
To: gdb-patches
Hi,
This is the first patch of the series. This piece didn't change since
the first iteraction.
http://sourceware.org/ml/gdb-patches/2012-03/msg00354.html
OK to check-in?
Thanks.
2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* ax-gdb.c (gen_expr): Clean up code to handle internal variables
and to compile agent expressions.
* infrun.c (siginfo_make_value): New argument `ignore'.
(siginfo_funcs): New struct.
(_initialize_infrun): New argument when calling
`create_internalvar_type_lazy'.
* thread.c (thread_id_make_value): New argument `ignore'.
(thread_funcs): New struct.
(_initialize_thread): New argument when calling
`create_internalvar_type_lazy'.
* tracepoint.c (sdata_make_value): New argument `ignore'.
(sdata_funcs): New struct.
(_initialize_tracepoint): New argument when calling
`create_internalvar_type_lazy'.
* value.c (make_value): New struct.
(create_internalvar_type_lazy): New argument `data'.
(compile_internalvar_to_ax): New function.
(value_of_internalvar): Properly handling `make_value' case.
(clear_internalvar): Likewise.
(show_convenience): Adding `TRY_CATCH' block.
* value.h (internalvar_make_value): Delete, replace by...
(struct internalvar_funcs): ... this.
(create_internalvar_type_lazy) <fun>: Delete argument.
(create_internalvar_type_lazy) <funcs>, <data>: New arguments.
(compile_internalvar_to_ax): New function.
* windows-tdep.c (tlb_make_value): New argument `ignore'.
(tlb_funcs): New struct.
(_initialize_windows_tdep): New argument when calling
`create_internalvar_type_lazy'.
---
gdb/ax-gdb.c | 5 +++--
gdb/infrun.c | 14 ++++++++++++--
gdb/thread.c | 14 ++++++++++++--
gdb/tracepoint.c | 14 ++++++++++++--
gdb/value.c | 44 +++++++++++++++++++++++++++++++++++++++-----
gdb/value.h | 48 +++++++++++++++++++++++++++++++++++++++++++++---
gdb/windows-tdep.c | 13 +++++++++++--
7 files changed, 134 insertions(+), 18 deletions(-)
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index aaefed6..eebe61a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2038,7 +2038,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;
(*pc) += 3;
@@ -2052,7 +2053,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a7d6c3c..c8a697a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6599,7 +6599,8 @@ static const struct lval_funcs siginfo_value_funcs =
if there's no object available. */
static struct value *
-siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
if (target_has_stack
&& !ptid_equal (inferior_ptid, null_ptid)
@@ -7021,6 +7022,15 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
"of all processes is %s.\n"), value);
}
+/* Implementation of `siginfo' variable. */
+
+static const struct internalvar_funcs siginfo_funcs =
+{
+ siginfo_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_infrun (void)
{
@@ -7309,7 +7319,7 @@ enabled by default on some platforms."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+ create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
add_setshow_boolean_cmd ("observer", no_class,
&observer_mode_1, _("\
diff --git a/gdb/thread.c b/gdb/thread.c
index 97f283c..d361dd8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1439,7 +1439,8 @@ update_thread_list (void)
no thread is selected, or no threads exist. */
static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);
@@ -1450,6 +1451,15 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
/* Commands with a prefix of `thread'. */
struct cmd_list_element *thread_cmd_list = NULL;
+/* Implementation of `thread' variable. */
+
+static const struct internalvar_funcs thread_funcs =
+{
+ thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1495,5 +1505,5 @@ Show printing of thread events (such as thread start and exit)."), NULL,
show_print_thread_events,
&setprintlist, &showprintlist);
- create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 86b6cfa..c213374 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4944,7 +4944,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
available. */
static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
@@ -5123,6 +5124,15 @@ traceframe_available_memory (VEC(mem_range_s) **result,
return 0;
}
+/* Implementation of `sdata' variable. */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
@@ -5133,7 +5143,7 @@ _initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
traceframe_number = -1;
tracepoint_number = -1;
diff --git a/gdb/value.c b/gdb/value.c
index eae3e2d..d498289 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1629,7 +1629,14 @@ struct internalvar
struct value *value;
/* The call-back routine used with INTERNALVAR_MAKE_VALUE. */
- internalvar_make_value make_value;
+ struct
+ {
+ /* The functions to call. */
+ const struct internalvar_funcs *functions;
+
+ /* The function's user-data. */
+ void *data;
+ } make_value;
/* The internal function used with INTERNALVAR_FUNCTION. */
struct
@@ -1728,18 +1735,39 @@ create_internalvar (const char *name)
/* Create an internal variable with name NAME and register FUN as the
function that value_of_internalvar uses to create a value whenever
this variable is referenced. NAME should not normally include a
- dollar sign. */
+ dollar sign. DATA is passed uninterpreted to FUN when it is
+ called. CLEANUP, if not NULL, is called when the internal variable
+ is destroyed. It is passed DATA as its only argument. */
struct internalvar *
-create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data)
{
struct internalvar *var = create_internalvar (name);
var->kind = INTERNALVAR_MAKE_VALUE;
- var->u.make_value = fun;
+ var->u.make_value.functions = funcs;
+ var->u.make_value.data = data;
return var;
}
+/* See documentation in value.h. */
+
+int
+compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value)
+{
+ if (var->kind != INTERNALVAR_MAKE_VALUE
+ || var->u.make_value.functions->compile_to_ax == NULL)
+ return 0;
+
+ var->u.make_value.functions->compile_to_ax (var, expr, value,
+ var->u.make_value.data);
+ return 1;
+}
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
@@ -1812,7 +1840,8 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;
case INTERNALVAR_MAKE_VALUE:
- val = (*var->u.make_value) (gdbarch, var);
+ val = (*var->u.make_value.functions->make_value) (gdbarch, var,
+ var->u.make_value.data);
break;
default:
@@ -2008,6 +2037,11 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;
+ case INTERNALVAR_MAKE_VALUE:
+ if (var->u.make_value.functions->destroy != NULL)
+ var->u.make_value.functions->destroy (var->u.make_value.data);
+ break;
+
default:
break;
}
diff --git a/gdb/value.h b/gdb/value.h
index 03aa5fd..76c8e85 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -764,10 +764,52 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
extern struct internalvar *create_internalvar (const char *name);
-typedef struct value * (*internalvar_make_value) (struct gdbarch *,
- struct internalvar *);
+/* An internalvar can be dynamically computed by supplying a vector of
+ function pointers to perform various operations. */
+
+struct internalvar_funcs
+{
+ /* Compute the value of the variable. The DATA argument passed to
+ the function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ struct value *(*make_value) (struct gdbarch *arch,
+ struct internalvar *var,
+ void *data);
+
+ /* Update the agent expression EXPR with bytecode to compute the
+ value. VALUE is the agent value we are updating. The DATA
+ argument passed to this function is the same argument that was
+ passed to `create_internalvar_type_lazy'. If this pointer is
+ NULL, then the internalvar cannot be compiled to an agent
+ expression. */
+
+ void (*compile_to_ax) (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ void *data);
+
+ /* If non-NULL, this is called to destroy DATA. The DATA argument
+ passed to this function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ void (*destroy) (void *data);
+};
+
extern struct internalvar *
- create_internalvar_type_lazy (char *name, internalvar_make_value fun);
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data);
+
+/* Compile an internal variable to an agent expression. VAR is the
+ variable to compile; EXPR and VALUE are the agent expression we are
+ updating. This will return 0 if there is no known way to compile
+ VAR, and 1 if VAR was successfully compiled. It may also throw an
+ exception on error. */
+
+extern int compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value);
extern struct internalvar *lookup_internalvar (const char *name);
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6b84eff..a704599 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -268,7 +268,7 @@ static const struct lval_funcs tlb_value_funcs =
if there's no object available. */
static struct value *
-tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore)
{
if (target_has_stack && !ptid_equal (inferior_ptid, null_ptid))
{
@@ -428,6 +428,15 @@ init_w32_command_list (void)
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_windows_tdep;
+/* Implementation of `tlb' variable. */
+
+static const struct internalvar_funcs tlb_funcs =
+{
+ tlb_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_windows_tdep (void)
{
@@ -454,5 +463,5 @@ even if their meaning is unknown."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_tlb", tlb_make_value);
+ create_internalvar_type_lazy ("_tlb", &tlb_funcs, NULL);
}
--
1.7.7.6
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 4/4 v3] Documentation and testsuite changes
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
` (2 preceding siblings ...)
2012-04-23 4:59 ` [PATCH 2/4 v3] Implement support for static and SystemTap probes Sergio Durigan Junior
@ 2012-04-23 6:35 ` Sergio Durigan Junior
2012-04-27 19:58 ` Tom Tromey
2012-04-28 23:30 ` Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes] Jan Kratochvil
4 siblings, 1 reply; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-23 6:35 UTC (permalink / raw)
To: gdb-patches
Hello,
This is the last patch. It contains doc & testsuite changes, and has
been already approved by Eli. I'm sending this either way.
I'll wait until the other patches are approved so that I can check it in
(of course).
Thanks.
gdb/doc/ChangeLog:
2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Static Probe Points): New entry, explaining SystemTap
and generic static probe support on GDB.
gdb/testsuite/ChangeLog:
2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* gdb.base/default.exp: Add `$_probe_arg*' convenience
variables.
* gdb.base/stap-probe.c: New file.
* gdb.base/stap-probe.exp: New file.
* gdb.trace/stap-trace.c: New file.
* gdb.trace/stap-trace.exp: New file.
* gdb.cp/nextoverthrow.exp: Add check for SystemTap probe in
libgcc's unwinder.
---
gdb/doc/gdb.texinfo | 91 ++++++++++++++++
gdb/testsuite/gdb.base/default.exp | 13 +++
gdb/testsuite/gdb.base/stap-probe.c | 108 +++++++++++++++++++
gdb/testsuite/gdb.base/stap-probe.exp | 183 ++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.cp/nextoverthrow.exp | 11 ++
gdb/testsuite/gdb.trace/stap-trace.c | 71 ++++++++++++
gdb/testsuite/gdb.trace/stap-trace.exp | 124 +++++++++++++++++++++
7 files changed, 601 insertions(+), 0 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/stap-probe.c
create mode 100644 gdb/testsuite/gdb.base/stap-probe.exp
create mode 100644 gdb/testsuite/gdb.trace/stap-trace.c
create mode 100644 gdb/testsuite/gdb.trace/stap-trace.exp
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e8be746..d15bc1e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3342,6 +3342,7 @@ all breakpoints in that range are operated on.
* Conditions:: Break conditions
* Break Commands:: Breakpoint command lists
* Save Breakpoints:: How to save breakpoints in a file
+* Static Probe Points:: Listing static probe points
* Error in Breakpoints:: ``Cannot insert breakpoints''
* Breakpoint-related Warnings:: ``Breakpoint address adjusted...''
@end menu
@@ -4652,6 +4653,69 @@ and remove the breakpoint definitions you're not interested in, or
that can no longer be recreated.
@end table
+@node Static Probe Points
+@subsection Static Probe Points
+
+@cindex static probe point, SystemTap
+@value{GDBN} supports @dfn{SDT} probes in the code. @acronym{SDT} stands
+for Statically Defined Tracing, and the probes are designed to have a tiny
+runtime code and data footprint, and no dynamic relocations. They are
+usable from assembly, C and C@t{++} languages. See
+@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
+for a good reference on how the @acronym{SDT} probes are implemented.
+
+Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
+@acronym{SDT} probes are supported on ELF-compatible systems. See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on how to add @code{SystemTap} @acronym{SDT} probes
+in your applications.
+
+@cindex semaphores on static probe points
+Some probes have an associated semaphore variable; for instance, this
+happens automatically if you defined your probe using a DTrace-style
+@file{.d} file. If your probe has a semaphore, @value{GDBN} will
+automatically enable it when you specify a breakpoint using the
+@samp{-probe-stap} notation. But, if you put a breakpoint at a probe's
+location by some other method (e.g., @code{break file:line}), then
+@value{GDBN} will not automatically set the semaphore.
+
+You can examine the available static static probes using @code{info
+probes}, with optional arguments:
+
+@table @code
+@kindex info probes
+@item info probes stap @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+If given, @var{provider} is a regular expression used to match against provider
+names when selecting which probes to list. If omitted, probes by all
+probes from all providers are listed.
+
+If given, @var{name} is a regular expression to match against probe names
+when selecting which probes to list. If omitted, probe names are not
+considered when deciding whether to display them.
+
+If given, @var{objfile} is a regular expression used to select which
+object files (executable or shared libraries) to examine. If not
+given, all object files are considered.
+
+@item info probes all
+List the available static probes, from all types.
+@end table
+
+@vindex $_probe_arg@r{, convenience variable}
+A probe may specify up to twelve arguments. These are available at the
+point at which the probe is defined---that is, when the current PC is
+at the probe's location. The arguments are available using the
+convenience variables (@pxref{Convenience Vars})
+@code{$_probe_arg0}@dots{}@code{$_probe_arg11}. Each probe argument is
+an integer of the appropriate size; types are not preserved. The
+convenience variable @code{$_probe_argc} holds the number of arguments
+at the current probe point.
+
+These variables are always available, but attempts to access them at
+any location other than a probe point will cause @value{GDBN} to give
+an error message.
+
+
@c @ifclear BARETARGET
@node Error in Breakpoints
@subsection ``Cannot insert breakpoints''
@@ -6667,6 +6731,19 @@ specify the function unambiguously, e.g., if there are several
functions with identical names in different source files.
@end table
+@cindex breakpoint at static probe point
+@item -pstap|-probe-stap @r{[}@var{objfile}:@r{[}@var{provider}:@r{]}@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes. @xref{Static Probe Points}, for more
+information on finding and using static probes. This form of linespec
+specifies the location of such a static probe.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable matching @var{objfile} as a regular expression are considered.
+If @var{provider} is given, then only probes from that provider are considered.
+If several probes match the spec, @value{GDBN} will insert a breakpoint at
+each one of those probes.
+
@end table
@@ -9071,6 +9148,10 @@ to match the format in which the data was printed.
The variable @code{$_exitcode} is automatically set to the exit code when
the program being debugged terminates.
+@item $_probe_argc
+@itemx $_probe_arg0@dots{}$_probe_arg11
+Arguments to a static probe. @xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, inspect, convenience variable}
The variable @code{$_sdata} contains extra collected static tracepoint
@@ -11015,6 +11096,16 @@ Collect all local variables.
Collect the return address. This is helpful if you want to see more
of a backtrace.
+@item $_probe_argc
+Collects the number of arguments from the static probe at which the
+tracepoint is located.
+@xref{Static Probe Points}.
+
+@item $_probe_arg@var{n}
+@var{n} is an integer between 0 and 11. Collects the @var{n}th argument
+from the static probe at which the tracepoint is located.
+@xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, collect}
Collect static tracepoint marker specific data. Only available for
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index c656a20..8c14708 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -604,6 +604,19 @@ gdb_test_list_exact "show convenience" "show convenience" \
{$_sdata = void} \
{$_siginfo = void} \
{$_thread = 0} \
+ {$_probe_argc = <error: No frame selected>} \
+ {$_probe_arg0 = <error: No frame selected>} \
+ {$_probe_arg1 = <error: No frame selected>} \
+ {$_probe_arg2 = <error: No frame selected>} \
+ {$_probe_arg3 = <error: No frame selected>} \
+ {$_probe_arg4 = <error: No frame selected>} \
+ {$_probe_arg5 = <error: No frame selected>} \
+ {$_probe_arg6 = <error: No frame selected>} \
+ {$_probe_arg7 = <error: No frame selected>} \
+ {$_probe_arg8 = <error: No frame selected>} \
+ {$_probe_arg9 = <error: No frame selected>} \
+ {$_probe_arg10 = <error: No frame selected>} \
+ {$_probe_arg11 = <error: No frame selected>} \
}
#test show directories
diff --git a/gdb/testsuite/gdb.base/stap-probe.c b/gdb/testsuite/gdb.base/stap-probe.c
new file mode 100644
index 0000000..1c7b05f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,108 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short test_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST test_user_semaphore
+
+__extension__ unsigned short test_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 test_two_semaphore
+
+__extension__ unsigned short test_m4_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short test_pstr_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short test_ps_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+struct funcs
+{
+ int val;
+
+ const char *(*ps) (int);
+};
+
+static void
+m1 (void)
+{
+ if (TEST2)
+ STAP_PROBE (test, two);
+}
+
+static void
+m2 (void)
+{
+ if (TEST2)
+ STAP_PROBE (test, two);
+}
+
+static int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1 (test, user, x);
+ return x+5;
+}
+
+static const char *
+pstr (int val)
+{
+ const char *a = "This is a test message.";
+ const char *b = "This is another test message.";
+
+ STAP_PROBE3 (test, ps, a, b, val);
+
+ return val == 0 ? a : b;
+}
+
+static void
+m4 (const struct funcs *fs, int v)
+{
+ STAP_PROBE3 (test, m4, fs->val, fs->ps (v), v);
+}
+
+int
+main()
+{
+ struct funcs fs;
+
+ fs.val = 42;
+ fs.ps = pstr;
+
+ f (f (23));
+ m1 ();
+ m2 ();
+
+ m4 (&fs, 0);
+ m4 (&fs, 1);
+
+ return 0; /* last break here */
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..9d51962
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,183 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+
+# 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/>.
+
+set testfile stap-probe
+
+# Run the tests. We run the tests two different ways: once with a
+# plain probe, and once with a probe that has an associated semaphore.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc stap_test {{arg ""}} {
+ global testfile hex
+
+ if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
+ [concat $arg debug]]} {
+ return -1
+ }
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+ "check argument not at probe point"
+
+ gdb_test "info probes stap" \
+ "test *user *$hex .*" \
+ "info probes stap"
+
+ if {[runto "-pstap test:user"]} {
+ pass "run to -pstap test:user"
+ } else {
+ fail "run to -pstap test:user"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user"
+ gdb_test "print \$_probe_arg0 == x" " = 1" \
+ "check \$_probe_arg0 for probe user"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user"
+
+ # Set a breakpoint with multiple probe locations.
+ gdb_test "break -pstap test:two" \
+ "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
+ "set multi-location probe breakpoint (probe two)"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:m4"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4"
+ gdb_test "print \$_probe_arg2 == v" " = 1" \
+ "check \$_probe_arg2 for probe m4"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:ps"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps"
+
+ return 0
+}
+
+proc stap_test_no_debuginfo {{ arg "" }} {
+ global testfile hex
+
+ if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
+ {$arg nodebug optimize=-O2}]} {
+ return -1
+ }
+
+ if {[runto "-pstap test:user"]} {
+ pass "run to -pstap test:user"
+ } else {
+ fail "run to -pstap test:user"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user"
+ gdb_test "print \$_probe_arg0 == 23" " = 1" \
+ "check \$_probe_arg0 for probe user"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user"
+
+ # Set a breakpoint with multiple probe locations.
+ # In this scenario, we may expect more than 2 locations because of
+ # the optimizations (inlining, loop unrolling, etc).
+ gdb_test "break -pstap test:two" \
+ "Breakpoint .* at $hex.*\[0-9\]+ locations.*" \
+ "set multi-location probe breakpoint (probe two)"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:m4"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4"
+ gdb_test "print \$_probe_arg2 == 0" " = 1" \
+ "check \$_probe_arg2 for probe m4"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:ps"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps"
+
+ return 0
+}
+
+with_test_prefix "without semaphore, not optimized" {
+ if {[stap_test] == -1} {
+ untested stap-probe.exp
+ return -1
+ }
+}
+
+with_test_prefix "with semaphore, not optimized" {
+ stap_test "-DUSE_PROBES"
+}
+
+with_test_prefix "without semaphore, optimized" {
+ stap_test_no_debuginfo
+}
+
+with_test_prefix "with semaphore, optimized" {
+ stap_test_no_debuginfo "-DUSE_PROBES"
+}
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 7d4a0c5..2dafcab 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -54,6 +54,17 @@ gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
}
}
if {!$ok} {
+ gdb_test_multiple "info probe" "check for stap probe in unwinder" {
+ -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
+ pass "check for stap probe in unwinder"
+ set ok 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+}
+
+if {!$ok} {
unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
return -1
}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.c b/gdb/testsuite/gdb.trace/stap-trace.c
new file mode 100644
index 0000000..7c638db
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.c
@@ -0,0 +1,71 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short test_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST test_user_semaphore
+
+__extension__ unsigned short test_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 test_two_semaphore
+
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif /* USE_PROBES */
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+void
+m1 (int x)
+{
+ if (TEST2)
+ STAP_PROBE1 (test, two, x);
+}
+
+int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1(test, user, x);
+ return x+5;
+}
+
+void
+nothing (void)
+{
+ int a = 1 + 1;
+ return;
+}
+
+int
+main()
+{
+ f (f (23));
+ m1 (46);
+ nothing (); /* end-here */
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.exp b/gdb/testsuite/gdb.trace/stap-trace.exp
new file mode 100644
index 0000000..c80759c
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.exp
@@ -0,0 +1,124 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# 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/>.
+
+load_lib "trace-support.exp"
+
+set testfile "stap-trace"
+set srcfile ${testfile}.c
+set executable $testfile
+set binfile $objdir/$subdir/$executable
+
+set ws "\[\r\n\t \]+"
+set cr "\[\r\n\]+"
+
+# Only x86 and x86_64 targets are supported for now.
+
+if { ![istarget "x86_64-*"] && ![istarget "i?86-*"] } {
+ continue
+}
+
+proc compile_stap_bin {{ arg "" }} {
+ global srcfile
+ global binfile
+ global srcdir
+ global subdir
+
+ if { $arg != "" } {
+ set arg "additional_flags=$arg"
+ }
+
+ if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+ executable [concat $arg debug nowarnings]] != "" } {
+ untested "Could not compile ${srcfile}"
+ return -1
+ }
+}
+
+proc prepare_for_trace_test {} {
+ global executable
+
+ clean_restart $executable
+
+ if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "end-here"]
+}
+
+proc run_trace_experiment { test_probe msg } {
+ global gdb_prompt
+
+ set test "collect $msg: start trace experiment"
+ gdb_test_multiple "tstart" "$test" {
+ -re "^tstart\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test "continue" \
+ "Continuing.*Breakpoint \[0-9\]+.*" \
+ "collect $msg: run trace experiment"
+ gdb_test "tstop" \
+ "\[\r\n\]+" \
+ "collect $msg: stop trace experiment"
+ gdb_test "tfind start" \
+ "#0 .*" \
+ "collect $msg: tfind test frame"
+}
+
+proc gdb_collect_probe_arg { msg probe val_arg0 } {
+ global gdb_prompt
+ global cr
+
+ prepare_for_trace_test
+
+ gdb_test "trace $probe" \
+ "Tracepoint \[0-9\]+ at .*" \
+ "collect $msg: set tracepoint"
+ gdb_trace_setactions "collect $msg: define actions" \
+ "" \
+ "collect \$_probe_arg0" "^$"
+
+ # Begin the test.
+ run_trace_experiment $msg $probe
+
+ gdb_test "print \$_probe_arg0" \
+ "\\$\[0-9\]+ = $val_arg0$cr" \
+ "collect $msg: collected probe arg0"
+}
+
+compile_stap_bin ""
+
+clean_restart $executable
+if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+}
+
+if { ![gdb_target_supports_trace] } {
+ # Test cannot run on this target.
+ return 1;
+}
+
+gdb_collect_probe_arg "probe args without semaphore" "-probe-stap user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "-probe-stap two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
--
1.7.7.6
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4 v3] Refactor internal variable mechanism
2012-04-23 4:59 ` [PATCH 1/4 v3] Refactor internal variable mechanism Sergio Durigan Junior
@ 2012-04-27 15:40 ` Tom Tromey
2012-04-27 20:57 ` Sergio Durigan Junior
0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2012-04-27 15:40 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> This is the first patch of the series. This piece didn't change since
Sergio> the first iteraction.
Sergio> http://sourceware.org/ml/gdb-patches/2012-03/msg00354.html
Sergio> OK to check-in?
Ok. Thanks.
Tom
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/4 v3] Implement support for static and SystemTap probes
2012-04-23 4:59 ` [PATCH 2/4 v3] Implement support for static and SystemTap probes Sergio Durigan Junior
@ 2012-04-27 19:43 ` Tom Tromey
2012-04-27 20:58 ` Sergio Durigan Junior
0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2012-04-27 19:43 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> This is the largest patch. It contains the fully abstracted API for
Sergio> creating static probes, and also the code for SystemTap probe.
Sergio> OK to check-in?
Ok.
Tom
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/4 v3] Use longjmp and exception probes when available
2012-04-23 4:59 ` [PATCH 3/4 v3] Use longjmp and exception probes when available Sergio Durigan Junior
@ 2012-04-27 19:47 ` Tom Tromey
2012-04-27 20:58 ` Sergio Durigan Junior
0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2012-04-27 19:47 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> This patch also almost didn't change from the first version.
Sergio> http://sourceware.org/ml/gdb-patches/2012-03/msg00356.html
Sergio> OK to check-in?
Yes, thanks.
Tom
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/4 v3] Documentation and testsuite changes
2012-04-23 6:35 ` [PATCH 4/4 v3] Documentation and testsuite changes Sergio Durigan Junior
@ 2012-04-27 19:58 ` Tom Tromey
2012-04-27 20:32 ` Tom Tromey
0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2012-04-27 19:58 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> +# Run the tests. We run the tests two different ways: once with a
Sergio> +# plain probe, and once with a probe that has an associated semaphore.
Sergio> +# This returns -1 on failure to compile or start, 0 otherwise.
Sergio> +proc stap_test {{arg ""}} {
[...]
Sergio> +proc stap_test_no_debuginfo {{ arg "" }} {
Sergio> + global testfile hex
Sergio> +
Sergio> + if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
[...]
I think it would be preferable if each different set of tests used a
different name for the built executable. This sort of thing makes it
simpler to debug failing tests. Also I think it is a newly agreed-upon
convention.
Sergio> diff --git a/gdb/testsuite/gdb.trace/stap-trace.exp b/gdb/testsuite/gdb.trace/stap-trace.exp
[...]
Sergio> +proc compile_stap_bin {{ arg "" }} {
[...]
Sergio> + if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
Sergio> + executable [concat $arg debug nowarnings]] != "" } {
Same here.
Tom
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/4 v3] Documentation and testsuite changes
2012-04-27 19:58 ` Tom Tromey
@ 2012-04-27 20:32 ` Tom Tromey
2012-04-27 20:57 ` Sergio Durigan Junior
2012-04-28 1:55 ` Sergio Durigan Junior
0 siblings, 2 replies; 19+ messages in thread
From: Tom Tromey @ 2012-04-27 20:32 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> I think it would be preferable if each different set of tests used a
Tom> different name for the built executable. This sort of thing makes it
Tom> simpler to debug failing tests. Also I think it is a newly agreed-upon
Tom> convention.
I neglected to mention, this is ok with that change.
Tom
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4 v3] Refactor internal variable mechanism
2012-04-27 15:40 ` Tom Tromey
@ 2012-04-27 20:57 ` Sergio Durigan Junior
0 siblings, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-27 20:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, April 27 2012, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> This is the first patch of the series. This piece didn't change since
> Sergio> the first iteraction.
>
> Sergio> http://sourceware.org/ml/gdb-patches/2012-03/msg00354.html
>
> Sergio> OK to check-in?
>
> Ok. Thanks.
Committed
http://sourceware.org/ml/gdb-cvs/2012-04/msg00226.html
Thanks.
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/4 v3] Documentation and testsuite changes
2012-04-27 20:32 ` Tom Tromey
@ 2012-04-27 20:57 ` Sergio Durigan Junior
2012-04-28 1:55 ` Sergio Durigan Junior
1 sibling, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-27 20:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, April 27 2012, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>
> Tom> I think it would be preferable if each different set of tests used a
> Tom> different name for the built executable. This sort of thing makes it
> Tom> simpler to debug failing tests. Also I think it is a newly agreed-upon
> Tom> convention.
>
> I neglected to mention, this is ok with that change.
Thanks, here is the updated version of the patch with the change. I
will commit the full series later.
--
Sergio
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6175b0e..f41118f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3342,6 +3342,7 @@ all breakpoints in that range are operated on.
* Conditions:: Break conditions
* Break Commands:: Breakpoint command lists
* Save Breakpoints:: How to save breakpoints in a file
+* Static Probe Points:: Listing static probe points
* Error in Breakpoints:: ``Cannot insert breakpoints''
* Breakpoint-related Warnings:: ``Breakpoint address adjusted...''
@end menu
@@ -4652,6 +4653,69 @@ and remove the breakpoint definitions you're not interested in, or
that can no longer be recreated.
@end table
+@node Static Probe Points
+@subsection Static Probe Points
+
+@cindex static probe point, SystemTap
+@value{GDBN} supports @dfn{SDT} probes in the code. @acronym{SDT} stands
+for Statically Defined Tracing, and the probes are designed to have a tiny
+runtime code and data footprint, and no dynamic relocations. They are
+usable from assembly, C and C@t{++} languages. See
+@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
+for a good reference on how the @acronym{SDT} probes are implemented.
+
+Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
+@acronym{SDT} probes are supported on ELF-compatible systems. See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on how to add @code{SystemTap} @acronym{SDT} probes
+in your applications.
+
+@cindex semaphores on static probe points
+Some probes have an associated semaphore variable; for instance, this
+happens automatically if you defined your probe using a DTrace-style
+@file{.d} file. If your probe has a semaphore, @value{GDBN} will
+automatically enable it when you specify a breakpoint using the
+@samp{-probe-stap} notation. But, if you put a breakpoint at a probe's
+location by some other method (e.g., @code{break file:line}), then
+@value{GDBN} will not automatically set the semaphore.
+
+You can examine the available static static probes using @code{info
+probes}, with optional arguments:
+
+@table @code
+@kindex info probes
+@item info probes stap @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+If given, @var{provider} is a regular expression used to match against provider
+names when selecting which probes to list. If omitted, probes by all
+probes from all providers are listed.
+
+If given, @var{name} is a regular expression to match against probe names
+when selecting which probes to list. If omitted, probe names are not
+considered when deciding whether to display them.
+
+If given, @var{objfile} is a regular expression used to select which
+object files (executable or shared libraries) to examine. If not
+given, all object files are considered.
+
+@item info probes all
+List the available static probes, from all types.
+@end table
+
+@vindex $_probe_arg@r{, convenience variable}
+A probe may specify up to twelve arguments. These are available at the
+point at which the probe is defined---that is, when the current PC is
+at the probe's location. The arguments are available using the
+convenience variables (@pxref{Convenience Vars})
+@code{$_probe_arg0}@dots{}@code{$_probe_arg11}. Each probe argument is
+an integer of the appropriate size; types are not preserved. The
+convenience variable @code{$_probe_argc} holds the number of arguments
+at the current probe point.
+
+These variables are always available, but attempts to access them at
+any location other than a probe point will cause @value{GDBN} to give
+an error message.
+
+
@c @ifclear BARETARGET
@node Error in Breakpoints
@subsection ``Cannot insert breakpoints''
@@ -6667,6 +6731,19 @@ specify the function unambiguously, e.g., if there are several
functions with identical names in different source files.
@end table
+@cindex breakpoint at static probe point
+@item -pstap|-probe-stap @r{[}@var{objfile}:@r{[}@var{provider}:@r{]}@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes. @xref{Static Probe Points}, for more
+information on finding and using static probes. This form of linespec
+specifies the location of such a static probe.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable matching @var{objfile} as a regular expression are considered.
+If @var{provider} is given, then only probes from that provider are considered.
+If several probes match the spec, @value{GDBN} will insert a breakpoint at
+each one of those probes.
+
@end table
@@ -9071,6 +9148,10 @@ to match the format in which the data was printed.
The variable @code{$_exitcode} is automatically set to the exit code when
the program being debugged terminates.
+@item $_probe_argc
+@itemx $_probe_arg0@dots{}$_probe_arg11
+Arguments to a static probe. @xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, inspect, convenience variable}
The variable @code{$_sdata} contains extra collected static tracepoint
@@ -11015,6 +11096,16 @@ Collect all local variables.
Collect the return address. This is helpful if you want to see more
of a backtrace.
+@item $_probe_argc
+Collects the number of arguments from the static probe at which the
+tracepoint is located.
+@xref{Static Probe Points}.
+
+@item $_probe_arg@var{n}
+@var{n} is an integer between 0 and 11. Collects the @var{n}th argument
+from the static probe at which the tracepoint is located.
+@xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, collect}
Collect static tracepoint marker specific data. Only available for
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index e2859d5..73fbe98 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -604,6 +604,19 @@ gdb_test_list_exact "show convenience" "show convenience" \
{$_sdata = void} \
{$_siginfo = void} \
{$_thread = 0} \
+ {$_probe_argc = <error: No frame selected>} \
+ {$_probe_arg0 = <error: No frame selected>} \
+ {$_probe_arg1 = <error: No frame selected>} \
+ {$_probe_arg2 = <error: No frame selected>} \
+ {$_probe_arg3 = <error: No frame selected>} \
+ {$_probe_arg4 = <error: No frame selected>} \
+ {$_probe_arg5 = <error: No frame selected>} \
+ {$_probe_arg6 = <error: No frame selected>} \
+ {$_probe_arg7 = <error: No frame selected>} \
+ {$_probe_arg8 = <error: No frame selected>} \
+ {$_probe_arg9 = <error: No frame selected>} \
+ {$_probe_arg10 = <error: No frame selected>} \
+ {$_probe_arg11 = <error: No frame selected>} \
}
#test show directories
diff --git a/gdb/testsuite/gdb.base/stap-probe.c b/gdb/testsuite/gdb.base/stap-probe.c
new file mode 100644
index 0000000..1c7b05f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,108 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short test_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST test_user_semaphore
+
+__extension__ unsigned short test_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 test_two_semaphore
+
+__extension__ unsigned short test_m4_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short test_pstr_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short test_ps_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+struct funcs
+{
+ int val;
+
+ const char *(*ps) (int);
+};
+
+static void
+m1 (void)
+{
+ if (TEST2)
+ STAP_PROBE (test, two);
+}
+
+static void
+m2 (void)
+{
+ if (TEST2)
+ STAP_PROBE (test, two);
+}
+
+static int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1 (test, user, x);
+ return x+5;
+}
+
+static const char *
+pstr (int val)
+{
+ const char *a = "This is a test message.";
+ const char *b = "This is another test message.";
+
+ STAP_PROBE3 (test, ps, a, b, val);
+
+ return val == 0 ? a : b;
+}
+
+static void
+m4 (const struct funcs *fs, int v)
+{
+ STAP_PROBE3 (test, m4, fs->val, fs->ps (v), v);
+}
+
+int
+main()
+{
+ struct funcs fs;
+
+ fs.val = 42;
+ fs.ps = pstr;
+
+ f (f (23));
+ m1 ();
+ m2 ();
+
+ m4 (&fs, 0);
+ m4 (&fs, 1);
+
+ return 0; /* last break here */
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..30ca427
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,183 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+
+# 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/>.
+
+set testfile stap-probe
+
+# Run the tests. We run the tests two different ways: once with a
+# plain probe, and once with a probe that has an associated semaphore.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc stap_test {exec_name {arg ""}} {
+ global testfile hex
+
+ if {[prepare_for_testing ${testfile}.exp ${exec_name} ${testfile}.c \
+ [concat $arg debug]]} {
+ return -1
+ }
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+ "check argument not at probe point"
+
+ gdb_test "info probes stap" \
+ "test *user *$hex .*" \
+ "info probes stap"
+
+ if {[runto "-pstap test:user"]} {
+ pass "run to -pstap test:user"
+ } else {
+ fail "run to -pstap test:user"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user"
+ gdb_test "print \$_probe_arg0 == x" " = 1" \
+ "check \$_probe_arg0 for probe user"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user"
+
+ # Set a breakpoint with multiple probe locations.
+ gdb_test "break -pstap test:two" \
+ "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
+ "set multi-location probe breakpoint (probe two)"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:m4"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4"
+ gdb_test "print \$_probe_arg2 == v" " = 1" \
+ "check \$_probe_arg2 for probe m4"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:ps"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps"
+
+ return 0
+}
+
+proc stap_test_no_debuginfo {exec_name {arg ""}} {
+ global testfile hex
+
+ if {[prepare_for_testing ${testfile}.exp ${exec_name} ${testfile}.c \
+ {$arg nodebug optimize=-O2}]} {
+ return -1
+ }
+
+ if {[runto "-pstap test:user"]} {
+ pass "run to -pstap test:user"
+ } else {
+ fail "run to -pstap test:user"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user"
+ gdb_test "print \$_probe_arg0 == 23" " = 1" \
+ "check \$_probe_arg0 for probe user"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user"
+
+ # Set a breakpoint with multiple probe locations.
+ # In this scenario, we may expect more than 2 locations because of
+ # the optimizations (inlining, loop unrolling, etc).
+ gdb_test "break -pstap test:two" \
+ "Breakpoint .* at $hex.*\[0-9\]+ locations.*" \
+ "set multi-location probe breakpoint (probe two)"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:m4"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4"
+ gdb_test "print \$_probe_arg2 == 0" " = 1" \
+ "check \$_probe_arg2 for probe m4"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-pstap test:ps"]} {
+ pass "run to -pstap test:m4"
+ } else {
+ fail "run to -pstap test:m4"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps"
+
+ return 0
+}
+
+with_test_prefix "without semaphore, not optimized" {
+ if {[stap_test "stap-probe-nosem-noopt"] == -1} {
+ untested stap-probe.exp
+ return -1
+ }
+}
+
+with_test_prefix "with semaphore, not optimized" {
+ stap_test "stap-probe-sem-noopt" "-DUSE_PROBES"
+}
+
+with_test_prefix "without semaphore, optimized" {
+ stap_test_no_debuginfo "stap-probe-nosem-opt"
+}
+
+with_test_prefix "with semaphore, optimized" {
+ stap_test_no_debuginfo "stap-probe-sem-opt" "-DUSE_PROBES"
+}
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 7d4a0c5..2dafcab 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -54,6 +54,17 @@ gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
}
}
if {!$ok} {
+ gdb_test_multiple "info probe" "check for stap probe in unwinder" {
+ -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
+ pass "check for stap probe in unwinder"
+ set ok 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+}
+
+if {!$ok} {
unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
return -1
}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.c b/gdb/testsuite/gdb.trace/stap-trace.c
new file mode 100644
index 0000000..7c638db
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.c
@@ -0,0 +1,71 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short test_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST test_user_semaphore
+
+__extension__ unsigned short test_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 test_two_semaphore
+
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif /* USE_PROBES */
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+void
+m1 (int x)
+{
+ if (TEST2)
+ STAP_PROBE1 (test, two, x);
+}
+
+int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1(test, user, x);
+ return x+5;
+}
+
+void
+nothing (void)
+{
+ int a = 1 + 1;
+ return;
+}
+
+int
+main()
+{
+ f (f (23));
+ m1 (46);
+ nothing (); /* end-here */
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.exp b/gdb/testsuite/gdb.trace/stap-trace.exp
new file mode 100644
index 0000000..562eec4
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.exp
@@ -0,0 +1,128 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# 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/>.
+
+load_lib "trace-support.exp"
+
+set testfile "stap-trace"
+set srcfile ${testfile}.c
+set executable ""
+set binfile_dir $objdir/$subdir
+
+set ws "\[\r\n\t \]+"
+set cr "\[\r\n\]+"
+
+# Only x86 and x86_64 targets are supported for now.
+
+if { ![istarget "x86_64-*"] && ![istarget "i?86-*"] } {
+ continue
+}
+
+proc compile_stap_bin {exec_name {arg ""}} {
+ global srcfile
+ global binfile_dir
+ global srcdir
+ global subdir
+ global executable
+
+ if { $arg != "" } {
+ set arg "additional_flags=$arg"
+ }
+
+ set executable ${exec_name}
+
+ if { [gdb_compile "$srcdir/$subdir/$srcfile" \
+ "$binfile_dir/$exec_name" \
+ executable [concat $arg debug nowarnings]] != "" } {
+ untested "Could not compile ${srcfile}"
+ return -1
+ }
+}
+
+proc prepare_for_trace_test {} {
+ global executable
+
+ clean_restart $executable
+
+ if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "end-here"]
+}
+
+proc run_trace_experiment { test_probe msg } {
+ global gdb_prompt
+
+ set test "collect $msg: start trace experiment"
+ gdb_test_multiple "tstart" "$test" {
+ -re "^tstart\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test "continue" \
+ "Continuing.*Breakpoint \[0-9\]+.*" \
+ "collect $msg: run trace experiment"
+ gdb_test "tstop" \
+ "\[\r\n\]+" \
+ "collect $msg: stop trace experiment"
+ gdb_test "tfind start" \
+ "#0 .*" \
+ "collect $msg: tfind test frame"
+}
+
+proc gdb_collect_probe_arg { msg probe val_arg0 } {
+ global gdb_prompt
+ global cr
+
+ prepare_for_trace_test
+
+ gdb_test "trace $probe" \
+ "Tracepoint \[0-9\]+ at .*" \
+ "collect $msg: set tracepoint"
+ gdb_trace_setactions "collect $msg: define actions" \
+ "" \
+ "collect \$_probe_arg0" "^$"
+
+ # Begin the test.
+ run_trace_experiment $msg $probe
+
+ gdb_test "print \$_probe_arg0" \
+ "\\$\[0-9\]+ = $val_arg0$cr" \
+ "collect $msg: collected probe arg0"
+}
+
+compile_stap_bin "stap-probe-nosem"
+
+clean_restart $executable
+if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+}
+
+if { ![gdb_target_supports_trace] } {
+ # Test cannot run on this target.
+ return 1;
+}
+
+gdb_collect_probe_arg "probe args without semaphore" "-probe-stap user" "23"
+gdb_exit
+
+compile_stap_bin "stap-probe-sem" "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "-probe-stap two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/4 v3] Use longjmp and exception probes when available
2012-04-27 19:47 ` Tom Tromey
@ 2012-04-27 20:58 ` Sergio Durigan Junior
0 siblings, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-27 20:58 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, April 27 2012, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> This patch also almost didn't change from the first version.
> Sergio> http://sourceware.org/ml/gdb-patches/2012-03/msg00356.htmlSergio> OK to check-in?
>
> Yes, thanks.
Thanks, checked in:
http://sourceware.org/ml/gdb-cvs/2012-04/msg00228.html
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/4 v3] Implement support for static and SystemTap probes
2012-04-27 19:43 ` Tom Tromey
@ 2012-04-27 20:58 ` Sergio Durigan Junior
0 siblings, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-27 20:58 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, April 27 2012, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> This is the largest patch. It contains the fully abstracted API for
> Sergio> creating static probes, and also the code for SystemTap probe.
>
> Sergio> OK to check-in?
>
> Ok.
Thanks, checked in:
http://sourceware.org/ml/gdb-cvs/2012-04/msg00227.html
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/4 v3] Documentation and testsuite changes
2012-04-27 20:32 ` Tom Tromey
2012-04-27 20:57 ` Sergio Durigan Junior
@ 2012-04-28 1:55 ` Sergio Durigan Junior
1 sibling, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-28 1:55 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, April 27 2012, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>
> Tom> I think it would be preferable if each different set of tests used a
> Tom> different name for the built executable. This sort of thing makes it
> Tom> simpler to debug failing tests. Also I think it is a newly agreed-upon
> Tom> convention.
>
> I neglected to mention, this is ok with that change.
Thanks, checked in:
http://sourceware.org/ml/gdb-cvs/2012-04/msg00229.html
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
* Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes]
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
` (3 preceding siblings ...)
2012-04-23 6:35 ` [PATCH 4/4 v3] Documentation and testsuite changes Sergio Durigan Junior
@ 2012-04-28 23:30 ` Jan Kratochvil
2012-04-29 6:29 ` Sergio Durigan Junior
4 siblings, 1 reply; 19+ messages in thread
From: Jan Kratochvil @ 2012-04-28 23:30 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
Hi Serigo,
On Mon, 23 Apr 2012 06:53:11 +0200, Sergio Durigan Junior wrote:
> Regtested on Fedora x86_64, no regressions. Comments are welcome.
-PASS: gdb.trace/backtrace.exp: run trace experiment
+ERROR: Process no longer exists
1786 loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
(gdb) p loc->probe
$1 = (struct probe *) 0x0
It happens only with gdbserver.
Thanks,
Jan
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes]
2012-04-28 23:30 ` Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes] Jan Kratochvil
@ 2012-04-29 6:29 ` Sergio Durigan Junior
2012-04-29 12:59 ` Jan Kratochvil
0 siblings, 1 reply; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-29 6:29 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On Saturday, April 28 2012, Jan Kratochvil wrote:
> On Mon, 23 Apr 2012 06:53:11 +0200, Sergio Durigan Junior wrote:
>> Regtested on Fedora x86_64, no regressions. Comments are welcome.
>
> -PASS: gdb.trace/backtrace.exp: run trace experiment
> +ERROR: Process no longer exists
> 1786 loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
> (gdb) p loc->probe
> $1 = (struct probe *) 0x0
>
> It happens only with gdbserver.
Thanks for catching this. I forgot to check if there is a probe before
setting/clearing the semaphore. This code fixes the problem. I am
committing it under the obvious rule.
Again, thanks for catching.
--
Sergio
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.14185
diff -u -p -r1.14185 ChangeLog
--- gdb/ChangeLog 28 Apr 2012 23:22:11 -0000 1.14185
+++ gdb/ChangeLog 28 Apr 2012 23:58:31 -0000
@@ -1,3 +1,8 @@
+2012-04-28 Sergio Durigan Junior <sergiodj@redhat.com>
+
+ * tracepoint.c (start_tracing, stop_tracing): Checking for NULL
+ probes, fixing a regression inserted by my previous patchset.
+
2012-04-28 Doug Evans <dje@google.com>
Initial support for Fission. http://gcc.gnu.org/wiki/DebugFission
Index: gdb/tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.253
diff -u -p -r1.253 tracepoint.c
--- gdb/tracepoint.c 27 Apr 2012 20:47:56 -0000 1.253
+++ gdb/tracepoint.c 28 Apr 2012 23:58:31 -0000
@@ -1783,7 +1783,8 @@ start_tracing (char *notes)
t->number_on_target = b->number;
for (loc = b->loc; loc; loc = loc->next)
- loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
+ if (loc->probe != NULL)
+ loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
}
VEC_free (breakpoint_p, tp_vec);
@@ -1878,7 +1879,8 @@ stop_tracing (char *note)
but we don't really care if this semaphore goes out of sync.
That's why we are decrementing it here, but not taking care
in other places. */
- loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
+ if (loc->probe != NULL)
+ loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
}
}
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes]
2012-04-29 6:29 ` Sergio Durigan Junior
@ 2012-04-29 12:59 ` Jan Kratochvil
2012-04-29 18:03 ` Sergio Durigan Junior
0 siblings, 1 reply; 19+ messages in thread
From: Jan Kratochvil @ 2012-04-29 12:59 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
On Sun, 29 Apr 2012 01:59:17 +0200, Sergio Durigan Junior wrote:
> I am committing it under the obvious rule.
I do not see it in CVS anywhere, HEAD still crashes, OK for check-in, check it
in, please.
> --- gdb/ChangeLog 28 Apr 2012 23:22:11 -0000 1.14185
> +++ gdb/ChangeLog 28 Apr 2012 23:58:31 -0000
> @@ -1,3 +1,8 @@
> +2012-04-28 Sergio Durigan Junior <sergiodj@redhat.com>
> +
> + * tracepoint.c (start_tracing, stop_tracing): Checking for NULL
> + probes, fixing a regression inserted by my previous patchset.
GNU Coding Standards paragraph starting with
There's no need to describe the full purpose of the changes
suggests more:
Fix a regression inserted by my previous patchset.
* tracepoint.c (start_tracing, stop_tracing): Check for NULL probes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes]
2012-04-29 12:59 ` Jan Kratochvil
@ 2012-04-29 18:03 ` Sergio Durigan Junior
0 siblings, 0 replies; 19+ messages in thread
From: Sergio Durigan Junior @ 2012-04-29 18:03 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
On Sunday, April 29 2012, Jan Kratochvil wrote:
> On Sun, 29 Apr 2012 01:59:17 +0200, Sergio Durigan Junior wrote:
>> I am committing it under the obvious rule.
>
> I do not see it in CVS anywhere, HEAD still crashes, OK for check-in, check it
> in, please.
You're right, I forgot to commit. How is that possible...
>> --- gdb/ChangeLog 28 Apr 2012 23:22:11 -0000 1.14185
>> +++ gdb/ChangeLog 28 Apr 2012 23:58:31 -0000
>> @@ -1,3 +1,8 @@
>> +2012-04-28 Sergio Durigan Junior <sergiodj@redhat.com>
>> +
>> + * tracepoint.c (start_tracing, stop_tracing): Checking for NULL
>> + probes, fixing a regression inserted by my previous patchset.
>
> GNU Coding Standards paragraph starting with
> There's no need to describe the full purpose of the changes
> suggests more:
>
> Fix a regression inserted by my previous patchset.
> * tracepoint.c (start_tracing, stop_tracing): Check for NULL probes.
Addressed.
Checked in:
http://sourceware.org/ml/gdb-cvs/2012-04/msg00242.html
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2012-04-29 15:16 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-23 4:57 [PATCH 0/4 v3] Add support for static and SystemTap probes Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 1/4 v3] Refactor internal variable mechanism Sergio Durigan Junior
2012-04-27 15:40 ` Tom Tromey
2012-04-27 20:57 ` Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 3/4 v3] Use longjmp and exception probes when available Sergio Durigan Junior
2012-04-27 19:47 ` Tom Tromey
2012-04-27 20:58 ` Sergio Durigan Junior
2012-04-23 4:59 ` [PATCH 2/4 v3] Implement support for static and SystemTap probes Sergio Durigan Junior
2012-04-27 19:43 ` Tom Tromey
2012-04-27 20:58 ` Sergio Durigan Junior
2012-04-23 6:35 ` [PATCH 4/4 v3] Documentation and testsuite changes Sergio Durigan Junior
2012-04-27 19:58 ` Tom Tromey
2012-04-27 20:32 ` Tom Tromey
2012-04-27 20:57 ` Sergio Durigan Junior
2012-04-28 1:55 ` Sergio Durigan Junior
2012-04-28 23:30 ` Regression for gdb.trace/backtrace.exp [Re: [PATCH 0/4 v3] Add support for static and SystemTap probes] Jan Kratochvil
2012-04-29 6:29 ` Sergio Durigan Junior
2012-04-29 12:59 ` Jan Kratochvil
2012-04-29 18:03 ` Sergio Durigan Junior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox