public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 4/6] Implement support for SystemTap probes
@ 2011-04-04  3:09 Sergio Durigan Junior
  2011-04-04 19:06 ` Eli Zaretskii
                   ` (3 more replies)
  0 siblings, 4 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-04-04  3:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Hi,

This is the biggest patch of the series.  It implements a bunch of new
functions used to support SystemTap probes (they live in
`stap-probe.[ch]'), and also modifies internal mechanisms to adapt them
to this new feature.  The patch also includes testcases, documentation,
and modifications on the tracepoint code to support collecting probe
arguments.

It is important to discuss some important aspects of the patch.  The
first one is the linespec change, needed to make GDB recognize the new
syntax for breaking at SystemTap probes.  This new syntax can be
expressed as:

(gdb) break probe:objfile:provider:name

It means that we are setting a breakpoint on a probe (the `probe:'
part), that this probe is located at the objfile name `objfile',
provider named `provider', and that the probe's name is `name'.  One can
also omit the `objfile:binary' part.  A real case example (the testcase
we are submitting with this patch) is:

(gdb) break probe:teste:user

Which means:  "Put a breakpoint in a SystemTap probe, which is located
at provider `teste', and whose name is `user'".

The other important aspect we think is worth bringing is the change
needed to implement the SystemTap probe's semaphore handling.  We had to
add a new field at `struct symtab_and_line' and to `struct bp_location'
in order to implement it.  We would appreciate if you take a look at
these modifications.

Finally, this patch was regtested on the compile farm, without any
regressions.

Thanks,

Sergio.

---
 gdb/ChangeLog                          |   60 +-
 gdb/Makefile.in                        |    8 +-
 gdb/NEWS                               |    4 +
 gdb/breakpoint.c                       |   43 +
 gdb/breakpoint.h                       |   12 +
 gdb/cli/cli-utils.c                    |   29 +
 gdb/cli/cli-utils.h                    |    7 +
 gdb/coffread.c                         |    1 +
 gdb/dbxread.c                          |    3 +-
 gdb/doc/ChangeLog                      |    4 +
 gdb/doc/gdb.texinfo                    |   82 ++
 gdb/elfread.c                          |  281 +++++
 gdb/linespec.c                         |    5 +
 gdb/machoread.c                        |    1 +
 gdb/mipsread.c                         |    1 +
 gdb/objfiles.c                         |    5 +
 gdb/somread.c                          |    1 +
 gdb/stap-probe.c                       | 2045 ++++++++++++++++++++++++++++++++
 gdb/stap-probe.h                       |  110 ++
 gdb/symfile.h                          |   55 +
 gdb/symtab.c                           |    1 +
 gdb/symtab.h                           |    4 +
 gdb/testsuite/ChangeLog                |   12 +
 gdb/testsuite/gdb.base/default.exp     |   11 +
 gdb/testsuite/gdb.base/stap-probe.c    |   69 ++
 gdb/testsuite/gdb.base/stap-probe.exp  |   72 ++
 gdb/testsuite/gdb.cp/nextoverthrow.exp |   11 +
 gdb/testsuite/gdb.trace/stap-trace.c   |   71 ++
 gdb/testsuite/gdb.trace/stap-trace.exp |  129 ++
 gdb/tracepoint.c                       |   26 +
 gdb/xcoffread.c                        |    1 +
 31 files changed, 3158 insertions(+), 6 deletions(-)
 create mode 100644 gdb/stap-probe.c
 create mode 100644 gdb/stap-probe.h
 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/ChangeLog b/gdb/ChangeLog
index 1fa276d..28e4711 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,61 @@
+2011-04-04  Sergio Durigan Junior  <sergiodj@redhat.com>
+	    Tom Tromey  <tromey@redhat.com>
+
+	* Makefile.in (SFILES): Add `stap-probe'.
+	(COMMON_OBS): Likewise.
+	(HFILES_NO_SRCDIR): Likewise.
+	* NEWS: Mention support for SystemTap probes.
+	* breakpoint.c: Include `gdb_regex.h' and `stap-probe.h'.
+	(modify_semaphore): New function.
+	(insert_bp_location): Call `modify_semaphore'.
+	(remove_breakpoint_1): Likewise.
+	(set_raw_breakpoint): Use the `semaphore' value.
+	(clone_momentary_breakpoint): Likewise.
+	(add_location_to_breakpoint): Likewise.
+	* breakpoint.h (struct bp_location) <semaphore>: New field.
+	(modify_semaphore): New function.
+	* cli/cli-utils.c (extract_arg): New function.
+	* cli/cli-utils.h (extract_arg): Likewise.
+	* coffread.c (coff_sym_fns): Add `sym_probe_fns' value.
+	* dbxread.c (aout_sym_fns): Likewise.
+	* elfread.c: Include `stap-probe.h' and `arch-utils.h'.
+	(stap_probe_key): New variable.
+	(struct stap_probe_per_objfile): New struct.
+	(handle_probe): New function.
+	(STAP_BASE_SECTION_NAME): New define.
+	(get_base_address_1): New function.
+	(get_base_address): Likewise.
+	(elf_get_probes): Likewise.
+	(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 SystemTap
+	probes.
+	* linespec.c (keep_name_info): Update comment in order to add the
+	`probe:' syntax.
+	(decode_line_1): Handle the `probe:' syntax.
+	* machoread.c (macho_sym_fns): Add `sym_probe_fns' value.
+	* mipsread.c (ecoff_sym_fns): Likewise.
+	* objfiles.c (objfile_relocate1): Support relocation for SystemTap
+	probes.
+	* 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 (struct sym_probe_fns): New struct.
+	(struct sym_fns) <sym_probe_fns>: New field.
+	* symtab.c (init_sal): Initialize `semaphore' field.
+	* symtab.h (struct symtab_and_line) <semaphore>: New field.
+	* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
+	locations.
+	(trace_stop_command): Likewise.
+	* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
+
 2011-04-04  Tom Tromey  <tromey@redhat.com>
 
 	* ax-gdb.c (gen_expr): Clean up code to handle internal variables
@@ -30,7 +88,7 @@
 	(_initialize_windows_tdep): New argument when calling
 	`create_internalvar_type_lazy'.
 
-2011-04-01  Tom Tromey  <tromey@redhat.com>
+2011-04-03  Tom Tromey  <tromey@redhat.com>
 
 	* breakpoint.c (create_breakpoints_sal): Added code to handle
 	pre-expanded sals.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6abd87a..8f8e7fc 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -721,8 +721,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 \
 	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 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 \
@@ -814,7 +814,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
-gnulib/stddef.in.h inline-frame.h
+gnulib/stddef.in.h inline-frame.h stap-probe.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -899,7 +899,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	prologue-value.o memory-map.o memrange.o xml-support.o xml-syscall.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
+	jit.o progspace.o stap-probe.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/NEWS b/gdb/NEWS
index a673d7a..2b87274 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -38,6 +38,10 @@
   Initial support for the OpenCL C language (http://www.khronos.org/opencl)
   has been integrated into GDB.
 
+* GDB now has support for SystemTap <sys/sdt.h> probes.  You can set a
+  breakpoint using the new "probe:" linespec and inspect the probe
+  arguments using the new $_probe_arg family of convenience variables.
+
 * Python scripting
 
   ** The function gdb.Write now accepts an optional keyword 'stream'.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3927171..8850f34 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -63,6 +63,8 @@
 #include "jit.h"
 #include "xml-syscall.h"
 #include "parser-defs.h"
+#include "gdb_regex.h"
+#include "stap-probe.h"
 #include "cli/cli-utils.h"
 
 /* readline include files */
@@ -1520,6 +1522,40 @@ should_be_inserted (struct bp_location *bl)
   return 1;
 }
 
+/* See the comment in breakpoint.h.  */
+
+void
+modify_semaphore (struct bp_location *loc, int set)
+{
+  struct gdbarch *arch = loc->gdbarch;
+  gdb_byte bytes[sizeof (LONGEST)];
+  /* The ABI specifies "unsigned short".  */
+  struct type *type = builtin_type (arch)->builtin_unsigned_short;
+  CORE_ADDR address = loc->semaphore;
+  ULONGEST value;
+
+  if (address == 0)
+    return;
+
+  /* Swallow errors.  */
+  if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
+    return;
+
+  value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
+				    gdbarch_byte_order (arch));
+  /* 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 (arch), value);
+
+  target_write_memory (address, bytes, TYPE_LENGTH (type));
+}
+
 /* Insert a low-level "breakpoint" of some type.  BL is the breakpoint
    location.  Any error messages are printed to TMP_ERROR_STREAM; and
    DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -1616,6 +1652,8 @@ insert_bp_location (struct bp_location *bl,
 	  else
 	    val = target_insert_breakpoint (bl->gdbarch,
 					    &bl->target_info);
+
+	  modify_semaphore (bl, 1);
 	}
       else
 	{
@@ -2553,6 +2591,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
 	    val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
 	  else
 	    val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+
+	  modify_semaphore (bl, 0);
 	}
       else
 	{
@@ -5902,6 +5942,7 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
   b->loc->requested_address = sal.pc;
   b->loc->address = adjusted_address;
   b->loc->pspace = sal.pspace;
+  b->loc->semaphore = sal.semaphore;
 
   /* Store the program space that was used to set the breakpoint, for
      breakpoint resetting.  */
@@ -7057,6 +7098,7 @@ clone_momentary_breakpoint (struct breakpoint *orig)
   copy->loc->address = orig->loc->address;
   copy->loc->section = orig->loc->section;
   copy->loc->pspace = orig->loc->pspace;
+  copy->loc->semaphore = orig->loc->semaphore;
 
   if (orig->source_file == NULL)
     copy->source_file = NULL;
@@ -7280,6 +7322,7 @@ add_location_to_breakpoint (struct breakpoint *b,
   loc->address = adjust_breakpoint_address (loc->gdbarch,
 					    loc->requested_address, b->type);
   loc->pspace = sal->pspace;
+  loc->semaphore = sal->semaphore;
   gdb_assert (loc->pspace != NULL);
   loc->section = sal->section;
 
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..8a91019 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -363,6 +363,11 @@ struct bp_location
      processor's architectual constraints.  */
   CORE_ADDR requested_address;
 
+  /* If the location comes from a SystemTap probe point, and the probe
+     has an associated semaphore variable, then this is the address of
+     the semaphore.  Otherwise, this is zero.  */
+  CORE_ADDR semaphore;
+
   char *function_name;
 
   /* Details of the placed breakpoint, when inserted.  */
@@ -1237,4 +1242,11 @@ extern struct breakpoint *iterate_over_breakpoints (int (*) (struct breakpoint *
 
 extern int user_breakpoint_p (struct breakpoint *);
 
+/* Set or clear a SystemTap semaphore.  LOC is the location which may
+   hold a semaphore.  SET is non-zero if the semaphore should be set,
+   or zero if the semaphore should be cleared.  Semaphores act as
+   reference counters, so calls to this function must be paired.  */
+
+extern void modify_semaphore (struct bp_location *location, int set);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index 62a2f12..dd2824f 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -245,3 +245,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 8a6e5b3..ed1a63e 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -103,4 +103,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 b11dd73..0868a79 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2193,6 +2193,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/dbxread.c b/gdb/dbxread.c
index 51ddd9d..a59ae10 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -1,6 +1,6 @@
 /* Read dbx symbol tables and convert to internal format, for GDB.
    Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
-   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010.
+   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010, 2011.
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -3587,6 +3587,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/doc/ChangeLog b/gdb/doc/ChangeLog
index 5225a6b..ce19cde 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2011-04-03  Tom Tromey  <tromey@redhat.com>
+
+	* gdb.texinfo (Static Probe Points): New entry.
+
 2011-04-02  Joel Brobecker  <brobecker@adacore.com>
 
 	* gdb.texinfo (GDB/MI Output Records): Fix menu entry for
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c71d664..9cb9bb5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3286,6 +3286,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
@@ -4499,6 +4500,50 @@ 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 SystemTap static probe point
+@cindex sdt-probe
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes, using @file{sys/sdt.h}.  @value{GDBN}
+can list the available probes, and you can put breakpoints at the
+probe points (@pxref{Specify Location}).
+
+You can examine the available @code{SystemTap} static probes using
+@code{info probes}:
+
+@table @code
+@kindex info probes
+@item info probes [@var{provider} [@var{name} [@var{objfile}]]]
+List the available @code{SystemTap} static probes.
+
+If given, @var{provider} is a regular expression used to select which
+providers to list.  If omitted, all providers are listed.
+
+If given, @var{name} is a regular expression used to select which
+probes to list.  If omitted, all probes are listed.
+
+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.
+@end table
+
+@vindex $_probe_arg@r{, convenience variable}
+A probe may specify up to ten 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_arg9}.  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.
+
+
 @c  @ifclear BARETARGET
 @node Error in Breakpoints
 @subsection ``Cannot insert breakpoints''
@@ -6414,6 +6459,29 @@ specify the function unambiguously, e.g., if there are several
 functions with identical names in different source files.
 @end table
 
+@cindex SystemTap static probe point
+@item probe:@r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes.  This form of linespec specifies
+the location of such a static probe.  See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on static probes.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable are considered.  If @var{provider} is given, then only
+probes from that provider are considered.
+
+@xref{Static Probe Points}, for more information on finding and using
+static probes.
+
+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:} 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.
+
 @end table
 
 
@@ -8500,6 +8568,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_arg9
+Arguments to a SystemTap static probe.  @xref{Static Probe Points}.
+
 @item $_sdata
 @vindex $_sdata@r{, inspect, convenience variable}
 The variable @code{$_sdata} contains extra collected static tracepoint
@@ -10219,6 +10291,16 @@ Collect all function arguments.
 @item $locals
 Collect all local variables.
 
+@item $_probe_argc
+Collects the number of arguments from the @code{SystemTap} probe at
+which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}
+
+@item $_probe_arg@var{N}
+Where @var{N} varies from 0 to 9.  Collects the @var{N}th argument
+from the @code{SystemTap} probe at which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}
+
 @item $_sdata
 @vindex $_sdata@r{, collect}
 Collect static tracepoint marker specific data.  Only available for
diff --git a/gdb/elfread.c b/gdb/elfread.c
index b9cfa13..a635e0b 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -38,6 +38,8 @@
 #include "demangle.h"
 #include "psympriv.h"
 #include "filenames.h"
+#include "stap-probe.h"
+#include "arch-utils.h"
 #include "gdbtypes.h"
 #include "value.h"
 #include "infcall.h"
@@ -61,6 +63,21 @@ struct elfinfo
     asection *mdebugsect;	/* Section pointer for .mdebug section */
   };
 
+/* Per-objfile data for SystemTap probe info.  */
+
+static const struct objfile_data *stap_probe_key = NULL;
+
+/* Per-objfile data about SystemTap probes.  */
+
+struct stap_probe_per_objfile
+  {
+    /* The number of probes in this objfile.  */
+    int stap_num_probes;
+
+    /* The probes themselves.  */
+    struct stap_probe *probes;
+  };
+
 static void free_elfinfo (void *);
 
 /* Minimal symbols located at the GOT entries for .plt - that is the real
@@ -1551,7 +1568,266 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
     complaint (&symfile_complaints,
 	       _("elf/stab section information missing for %s"), filename);
 }
+
+/* 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.  */
+
+static void
+handle_probe (struct objfile *objfile, struct sdt_note *el,
+	      struct stap_probe *ret, CORE_ADDR base)
+{
+  bfd *abfd = objfile->obfd;
+  int size = bfd_get_arch_size (abfd) / 8;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+  CORE_ADDR base_ref;
+
+  /* Provider and the name of the probe.  */
+  ret->provider = (const char *) &el->data[3 * size];
+  ret->name = memchr (ret->provider, '\0',
+		      (unsigned long *) el->data
+		      + el->size - (unsigned long *) ret->provider);
+  /* Making sure there is a name.  */
+  if (!ret->name)
+    complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+	       objfile->name);
+  else
+    ++ret->name;
+
+  /* Retrieving the probe's address.  */
+  ret->address = extract_typed_address ((const gdb_byte *) &el->data[0],
+					ptr_type);
+  /* Link-time sh_addr of `.stapsdt.base' section.  */
+  base_ref = extract_typed_address ((const gdb_byte *) &el->data[size],
+				    ptr_type);
+  /* Semaphore address.  */
+  ret->sem_addr = extract_typed_address ((const gdb_byte *) &el->data[2 * size],
+					 ptr_type);
+
+  ret->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.  */
+  if (ret->name)
+    {
+      ret->args = memchr (ret->name, '\0',
+			  (unsigned long *) el->data
+			  + el->size - (unsigned long *) ret->name);
+
+      if (ret->args++ != NULL
+	  || memchr (ret->args, '\0', (unsigned long *) el->data
+		     + el->size - (unsigned long *) ret->name)
+	  != el->data + el->size - 1)
+	complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+		   objfile->name);
+    }
+  else
+    ret->args = NULL;
+}
+
+/* The name of the SystemTap section where we will find information about
+   the probes.  */
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
+/* Helper function which tries to find the base address of the SystemTap
+   base section named STAP_BASE_SECTION_NAME.  */
+
+static void
+get_base_address_1 (bfd *abfd, asection *sect, void *obj)
+{
+  bfd_vma *base = (bfd_vma *) obj;
+
+  if (*base == (bfd_vma) -1
+      && (sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
+      && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
+    *base = sect->vma;
+}
+
+/* Helper function which iterates over every section in the BFD file,
+   trying to find the base address of the SystemTap base section.
+   Returns the section address if found, or -1 otherwise.  */
+
+static bfd_vma
+get_base_address (bfd *obfd)
+{
+  bfd_vma base = (bfd_vma) -1;
+
+  bfd_map_over_sections (obfd, get_base_address_1, (void *) &base);
+
+  return base;
+}
+
+/* Implementation of `sym_get_probes', as documented in symfile.h.  */
+
+static const struct stap_probe *
+elf_get_probes (struct objfile *objfile, int *num_probes)
+{
+  struct stap_probe *ret = NULL;
+  struct stap_probe_per_objfile *probes_per_objfile;
+
+  /* Initially, no probes.  */
+  *num_probes = 0;
+
+  /* Have we parsed this objfile's probes already?  */
+  probes_per_objfile
+    = (struct stap_probe_per_objfile *) objfile_data (objfile,
+						      stap_probe_key);
+
+  if (!probes_per_objfile)
+    {
+      /* If we are here, then this is the first time we are parsing the
+	 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 = get_base_address (obfd);
+      struct sdt_note *iter;
+      int i;
+      int n = 0;
+
+      if (! elf_tdata (obfd)->sdt_note_head)
+	/* There isn't any probe here.  */
+	return NULL;
+
+      /* Allocating space for probe info.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head;
+	   iter;
+	   iter = iter->next, ++n);
+
+      ret = xcalloc (n, sizeof (struct stap_probe));
+
+      /* Parsing each probe's information.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
+	   iter;
+	   iter = iter->next, i++)
+	/* We first have to handle all the information about the
+	   probe which is present in the section.  */
+	handle_probe (objfile, iter, &ret[i], base);
+
+      /* Creating a cache for these probes in the objfile's registry.  */
+      probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
+
+      probes_per_objfile->stap_num_probes = n;
+      probes_per_objfile->probes = ret;
+
+      set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
+    }
+  else
+    ret = probes_per_objfile->probes;
+
+  *num_probes = probes_per_objfile->stap_num_probes;
+
+  return ret;
+}
+
+/* Implementation of `sym_get_probe_argument_count', as documented in
+   symfile.h.  */
+
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+			      const struct stap_probe *probe)
+{
+  const char *pargs = probe->args;
+
+  if (!pargs || !*pargs || *pargs == ':')
+    /* No arguments.  */
+    return 0;
+
+  return stap_get_probe_argument_count (probe);
+}
+
+/* Implementation of `sym_evaluate_probe_argument', as documented in
+   symfile.h.  */
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+			     const struct stap_probe *probe,
+			     struct frame_info *frame,
+			     int n)
+{
+  return stap_evaluate_probe_argument (objfile, probe, frame, n);
+}
+
+/* Implementation of `sym_compile_to_ax', as documented in symfile.h.  */
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+		   const struct stap_probe *probe,
+		   struct agent_expr *expr,
+		   struct axs_value *value,
+		   int n)
+{
+  stap_compile_to_ax (objfile, probe, 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 i;
+  struct stap_probe_per_objfile *p
+    = (struct stap_probe_per_objfile *) objfile_data (objfile,
+						      stap_probe_key);
+
+  if (!p)
+    /* No probe to relocate.  */
+    return;
+
+  for (i = 0; i < p->stap_num_probes; i++)
+    {
+      p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      if (p->probes[i].sem_addr)
+	p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
+    }
+}
+
+/* Helper function used to free the space allocated for storing SystemTap
+   probe information.  */
+
+static void
+stap_probe_key_free (struct objfile *objfile, void *d)
+{
+  int i;
+  struct stap_probe_per_objfile *data = (struct stap_probe_per_objfile *) d;
+
+  for (i = 0; i < data->stap_num_probes; i++)
+    stap_free_parsed_args (data->probes[i].parsed_args);
+  xfree (data->probes);
+  xfree (data);
+}
+
 \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 =
@@ -1566,6 +1842,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
 };
 
@@ -1584,6 +1861,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
 };
 
@@ -1601,6 +1879,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
 };
 
@@ -1617,6 +1896,8 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
 void
 _initialize_elfread (void)
 {
+  stap_probe_key
+    = register_objfile_data_with_cleanup (NULL, stap_probe_key_free);
   add_symtab_fns (&elf_sym_fns);
 
   elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 70df3ca..af53f97 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -43,6 +43,7 @@
 #include "arch-utils.h"
 #include <ctype.h>
 #include "cli/cli-utils.h"
+#include "stap-probe.h"
 
 /* We share this one with symtab.c, but it is not exported widely.  */
 
@@ -762,6 +763,7 @@ keep_name_info (char *ptr)
    PC returned is 0.
    FILE:FUNCTION -- likewise, but prefer functions in that file.
    *EXPR -- line in which address EXPR appears.
+   probe:[OBJFILE:][PROVIDER:]NAME -- a systemtap static probe
 
    This may all be followed by an "if EXPR", which we ignore.
 
@@ -837,6 +839,9 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
   if (**argptr == '*')
     return decode_indirect (argptr);
 
+  if (strncmp (*argptr, "probe:", 6) == 0)
+    return parse_stap_probe (argptr, canonical, not_found_ptr);
+
   is_quoted = (strchr (get_gdb_completer_quote_characters (),
 		       **argptr) != NULL);
 
diff --git a/gdb/machoread.c b/gdb/machoread.c
index dbf9ae4..3db9e16 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -849,6 +849,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 74d795d..7e05317 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -402,6 +402,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 f3259dd..4cb3bed 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -846,6 +846,11 @@ objfile_relocate1 (struct objfile *objfile,
 				obj_section_addr (s));
     }
 
+  /* Relocating SystemTap 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/somread.c b/gdb/somread.c
index 70831a0..baf68ea 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -439,6 +439,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..d491067
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,2045 @@
+/* SystemTap probe support for GDB.
+
+   Copyright (C) 2011 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 "vec.h"
+#include "ui-out.h"
+#include "gdb_regex.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "filenames.h"
+#include "value.h"
+#include "exceptions.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "user-regs.h"
+#include "complaints.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
+
+#include <ctype.h>
+
+/* 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 string representing this argument.  */
+  char *arg_str;
+};
+
+/* The maximum number of arguments that a probe can have,
+   as defined in <sys/sdt.h>.  */
+
+#define STAP_MAX_ARGS 10
+
+/* Structure that holds information about all arguments of a probe.  */
+
+struct stap_args_info
+{
+  /* The number of valid parsed arguments.  */
+  int n_args;
+
+  /* The probe to which these arguments belong.  */
+  struct stap_probe *probe;
+
+  /* Information about each argument.  */
+  struct stap_probe_arg *arg;
+};
+
+/* Structure that contains all the necessary information to evaluate
+   an expression.  */
+
+struct stap_evaluation_info
+{
+  /* The constant pointer which holds the expression. This is primarily
+     used for printing error messages.  Evaluation functions should
+     not modify this pointer directly; instead, they should use the
+     EXP_BUFFER pointer below.  */
+  const char *saved_expr;
+
+  /* Modifiable version of the above pointer.  */
+  char *exp_buf;
+
+  /* The pointer to the current gdbarch.  */
+  struct gdbarch *gdbarch;
+
+  /* The pointer to the current frame, used when accessing registers'
+     contents.  */
+  struct frame_info *frame;
+
+  /* The bitness specified for this argument.  */
+  enum stap_arg_bitness bitness;
+
+  /* Flag to indicate if we are compiling an agent expression.  */
+  int compiling_p;
+
+  /* If the above flag is true (one), this field will contain the
+     pointer to the agent expression.  */
+  struct agent_expr *aexpr;
+
+  /* The value we are modifying (for agent expression).  */
+  struct axs_value *avalue;
+};
+
+/* This dummy variable is used when parsing a probe's argument fails.
+   In this case, the number of arguments for this probe is zero, so that's
+   why this variable is useful.  */
+
+static struct stap_args_info dummy_stap_args_info =
+  { 0, NULL, NULL };
+
+static struct value *stap_evaluate_probe_argument_2
+  (struct stap_evaluation_info *eval_info,
+   struct value *lhs, int prec);
+
+static struct value *stap_evaluate_conditionally
+  (struct stap_evaluation_info *eval_info);
+
+/* Helper function which decides to skip whitespaces or not in a probe's
+   argument string.  Basically, if we are inside a parenthesis expression
+   (i.e., inside a subexpression), we can skip whitespaces; otherwise we
+   cannot.  */
+
+static void
+stap_skip_whitespace_cond (char **s, int inside_paren)
+{
+  if (inside_paren)
+    *s = skip_spaces (*s);
+}
+
+/* Helper function which parses a single argument in a probe's argument
+   string, based on various rules (which can be learned from the `gas'
+   manual).  It returns 1 on success, or 0 otherwise.  */
+
+static int
+stap_parse_arg (const char **p)
+{
+  char *cur = (char *) *p;
+  int done = 0;
+  int paren_open = 0;
+
+  while (!done)
+    {
+      switch (*cur)
+	{
+	case ' ': case 0:
+	  /* If we're here, then we have already parsed everything
+	     from this argument.  */
+	  if (paren_open)
+	    return 0;
+	  done = 1;
+	  break;
+
+	case '(':
+	  ++paren_open;
+	  ++cur;
+	  stap_skip_whitespace_cond (&cur, paren_open);
+	  break;
+
+	case ')':
+	  if (!paren_open)
+	    return 0;
+
+	  --paren_open;
+	  ++cur;
+	  if (paren_open)
+	    cur = skip_spaces (cur);
+	  break;
+
+	case '+': case '-':
+	case '*': case '/':
+	case '>': case '<': case '|': case '&':
+	case '^': case '!':
+	    {
+	      char c = *cur;
+
+	      ++cur;
+	      switch (*cur)
+		{
+		case '>':
+		  if (c != '<' && c != '>')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '<':
+		  if (c != '<')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '=':
+		  if (c != '=' && c != '<' && c != '>' && c != '!')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '|':
+		  if (c != '|')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '&':
+		  if (c != '&')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		default:
+		  break;
+		}
+	      /* Infix operators take two arguments, one on either
+		 side.  Skipping the whitespaces that may happen on the
+		 right side.  */
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	    }
+	  break;
+
+	case '%':
+	    {
+	      ++cur;
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	      if (*cur >= 'a' && *cur <= 'z')
+		{
+		  /* We're dealing with a register name.  */
+		  while (isalnum (*cur))
+		    ++cur;
+
+		  stap_skip_whitespace_cond (&cur, paren_open);
+
+		  /* Some registers (e.g. floating-point register stack
+		     registers on Intel i386) have the following syntax:
+
+		     `%st(0)', `%st(1)', and so on.
+
+		     So it's ok to expect parenthesis here.  */
+		  if (*cur == '(')
+		    {
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		      if (!isdigit (*cur))
+			/* This is an error, since we only expect numbers
+			   inside this parenthesis.  */
+			return 0;
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		      if (*cur != ')')
+			/* We only expect one number.  */
+			return 0;
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		    }
+		}
+	    }
+	  break;
+
+	case '$':
+	    {
+	      /* This is an integer constant.  */
+	      ++cur;
+	      stap_skip_whitespace_cond (&cur, paren_open);
+
+	      while (isdigit (*cur))
+		++cur;
+
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	    }
+	  break;
+
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+	    {
+	      char *old = cur;
+
+	      /* Number.  */
+	      while (isdigit (*cur))
+		++cur;
+
+	      /* We have to do a lookahead here, because the user may
+		 input `2 + 2' (with spaces), and this is not an error.  */
+	      cur = skip_spaces (cur);
+
+	      switch (*cur)
+		{
+		case '+': case '-':
+		  /* We may find the `@' sign, and it means that the
+		     argument has finished, so we shouldn't advance the
+		     pointer.  */
+		  if (cur[1] && (cur[1] == '4' || cur[1] == '8')
+		      && cur[2] && cur[2] == '@')
+		    {
+		      cur = old;
+		      goto fin;
+		    }
+		  break;
+
+		case '*': case '/': case '>': case '<':
+		case '|': case '&': case '^': case '!':
+		  /* This is a binary operation, which means we'll
+		     have to find another number after the operator.  */
+		  break;
+
+		case '(':
+		  /* We may also have sentences in the form:
+
+		     `4 (%rax)'  */
+		  break;
+		}
+	    }
+fin:
+	  break;
+	}
+    }
+
+  *p = cur;
+
+  return 1;
+}
+
+/* Helper function which is responsible for freeing the space allocated to
+   hold information about a probe's arguments.  */
+
+static void
+stap_free_args_info (void *args_info_ptr)
+{
+  struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
+  int i;
+
+  for (i = 0; i < STAP_MAX_ARGS; i++)
+    {
+      xfree (a->arg->arg_str);
+    }
+
+  xfree (a->arg);
+  xfree (a);
+}
+
+/* Function which parses an argument string from PROBE, correctly splitting
+   the arguments and storing their information in properly ways.  This function
+   only separates the arguments, but does not evaluate them.
+
+   Consider the following argument string:
+
+   `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 stap_args_info *args_info;
+  struct cleanup *back_to;
+  const char *cur = probe->args;
+  int current_arg = -1;
+  /* This is a state-machine parser, which means we will always be
+     in a known state when parsing an argument.  The state could be
+     either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
+     we are parsing the bitness-definition part (i.e., `4@'), or
+     `PARSE_ARG' if we are actually parsing the argument part.  */
+  enum
+    {
+      NEW_ARG,
+      BITNESS,
+      PARSE_ARG,
+    } current_state;
+
+  /* For now, we assume everything is not going to work.  */
+  probe->parsed_args = &dummy_stap_args_info;
+
+  if (!cur || !*cur || *cur == ':')
+    return;
+
+  args_info = xmalloc (sizeof (struct stap_args_info));
+  back_to = make_cleanup (stap_free_args_info, args_info);
+  args_info->arg = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
+
+  /* Ok, let's start.  */
+  current_state = NEW_ARG;
+
+  while (*cur)
+    {
+      switch (current_state)
+	{
+	case NEW_ARG:
+	  ++current_arg;
+
+	  if (current_arg >= STAP_MAX_ARGS)
+	    {
+	      complaint (&symfile_complaints,
+			 _("probe `%s' has more arguments than the maximum "
+			   "allowed"), probe->name);
+	      do_cleanups (back_to);
+	      return;
+	    }
+
+	  current_state = BITNESS;
+	  break;
+
+	case BITNESS:
+	    {
+	      enum stap_arg_bitness b;
+	      int got_minus = 0;
+
+	      /* 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] != '@')
+		{
+		  current_state = PARSE_ARG;
+		  args_info->arg[current_arg].bitness
+		    = STAP_ARG_BITNESS_UNDEFINED;
+		  break;
+		}
+
+	      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->name);
+		  do_cleanups (back_to);
+		  return;
+		}
+
+	      args_info->arg[current_arg].bitness = b;
+	      /* Discard the number and the `@' sign.  */
+	      cur += 2;
+	      /* Move on.  */
+	      current_state = PARSE_ARG;
+	    }
+	  break;
+
+	case PARSE_ARG:
+	    {
+	      const char *start = cur;
+
+	      if (!stap_parse_arg (&cur))
+		{
+		  /* We have tried to parse this argument, but it's
+		     malformed.  This is an error.  */
+		  do_cleanups (back_to);
+		  return;
+		}
+
+	      args_info->arg[current_arg].arg_str
+		= savestring (start, cur - start);
+	      /* Start it over again.  */
+	      cur = skip_spaces ((char *) cur);
+	      current_state = NEW_ARG;
+	    }
+	  break;
+	}
+
+      if (!*cur && current_state != NEW_ARG)
+	{
+	  /* We reached the end of the argument string, but we're
+	     still in the middle of the process of parsing an argument.
+	     It means the argument string is malformed.  */
+	  complaint (&symfile_complaints,
+		     _("malformed argument for probe `%s'"),
+		     probe->name);
+	  do_cleanups (back_to);
+	  return;
+	}
+    }
+
+  args_info->n_args = current_arg + 1;
+  args_info->arg = xrealloc (args_info->arg,
+			      args_info->n_args
+			      * sizeof (struct stap_probe_arg));
+  args_info->probe = probe;
+
+  probe->parsed_args = args_info;
+
+  discard_cleanups (back_to);
+}
+
+/* See definition in stap-probe.h.  */
+
+int
+stap_get_probe_argument_count (const struct stap_probe *probe)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  return probe->parsed_args->n_args;
+}
+
+/* Returns the operator precedence level of OP, or zero if the operator
+   code was not recognized.
+   The levels were taken from the gas manual.  */
+
+static int
+stap_get_operator_prec (enum exp_opcode op)
+{
+  switch (op)
+    {
+    case BINOP_LOGICAL_OR:
+      return 1;
+
+    case BINOP_LOGICAL_AND:
+      return 2;
+
+    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 3;
+
+    case BINOP_BITWISE_IOR: case BINOP_BITWISE_AND:
+    case BINOP_BITWISE_XOR: case UNOP_LOGICAL_NOT:
+      return 4;
+
+    case BINOP_MUL: case BINOP_DIV: case BINOP_REM:
+    case BINOP_LSH: case BINOP_RSH:
+      return 5;
+
+    default:
+      return 0;
+    }
+}
+
+/* Given S, this function reads the operator in it and fills the OP
+   pointer with its code.  Returns 1 on success, zero if the operator
+   was not recognized.  */
+
+static int
+stap_get_opcode (char **s, enum exp_opcode *op)
+{
+  char c = **s;
+  int ret = 1;
+
+  *s += 1;
+
+  switch (c)
+    {
+    case '*':
+      *op = BINOP_MUL;
+      break;
+
+    case '/':
+      *op = BINOP_DIV;
+      break;
+
+    case '%':
+      {
+	if (isalpha (**s))
+	  {
+	    /* Dealing with a register name.  */
+	    ret = 0;
+	    break;
+	  }
+
+	*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 operator OPCODE, this function generates agent bytecode
+   for it.  */
+
+static void
+stap_opcode_to_ax (struct stap_evaluation_info *eval_info,
+		   enum exp_opcode opcode)
+{
+  struct agent_expr *expr = eval_info->aexpr;
+
+  switch (opcode)
+    {
+    case BINOP_MUL:
+      ax_simple (expr, aop_mul);
+      break;
+
+    case BINOP_DIV:
+      ax_simple (expr, aop_div_signed);
+      break;
+
+    case BINOP_REM:
+      ax_simple (expr, aop_rem_unsigned);
+      break;
+
+    case BINOP_LESS:
+      ax_simple (expr, aop_less_signed);
+      break;
+
+    case BINOP_LEQ:
+      /* A <= B is !(B < A) */
+      ax_simple (expr, aop_swap);
+      ax_simple (expr, aop_less_signed);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_GTR:
+      /* A > B is B < A */
+      ax_simple (expr, aop_swap);
+      ax_simple (expr, aop_less_signed);
+      break;
+
+    case BINOP_GEQ:
+      /* A >= B is !(A < B) */
+      ax_simple (expr, aop_less_signed);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_NOTEQUAL:
+      ax_simple (expr, aop_equal);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_LSH:
+      ax_simple (expr, aop_lsh);
+      break;
+
+    case BINOP_RSH:
+      ax_simple (expr, aop_rsh_unsigned);
+      break;
+
+    case BINOP_BITWISE_IOR:
+      ax_simple (expr, aop_bit_or);
+      break;
+     
+    case BINOP_LOGICAL_OR:
+      error (_("Operator logical-or (`||') not supported yet."));
+      break;
+
+    case BINOP_BITWISE_AND:
+      ax_simple (expr, aop_bit_and);
+      break;
+
+    case BINOP_LOGICAL_AND:
+      error (_("Operator logical-and (`&&') not supported yet."));
+      break;
+
+    case BINOP_BITWISE_XOR:
+      ax_simple (expr, aop_bit_xor);
+      break;
+
+    case UNOP_LOGICAL_NOT:
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_ADD:
+      ax_simple (expr, aop_add);
+      break;
+
+    case BINOP_SUB:
+      ax_simple (expr, aop_sub);
+      break;
+
+    case BINOP_EQUAL:
+      ax_simple (expr, aop_equal);
+      break;
+
+    default:
+      error (_("Invalid operator."));
+    }
+}
+
+/* Returns 1 if *S is an operator, zero otherwise.  */
+
+static int
+stap_is_operator (char *s)
+{
+  char op;
+
+  if (!s || !*s)
+    return 0;
+
+  op = *s;
+
+  if (*s == '%' && isalpha (s[1]))
+    /* Register name.  */
+    return 0;
+
+  return (op == '+' || op == '-' || op == '*' || op == '/'
+	  || op == '>' || op == '<' || op == '!' || op == '^'
+	  || op == '|' || op == '&' || op == '%' || op == '=');
+}
+
+/* This function fetches the value of the register whose
+   name starts in the expression buffer.  It also applies any register
+   displacements (e.g., `-4(%eax)'), and indirects the contents of the
+   register (e.g., `(%eax)').  It returns RET if the operation has succeeded,
+   or calls `error' otherwise.  */
+
+static struct value *
+stap_fetch_reg_value (struct stap_evaluation_info *eval_info,
+		      struct value *displacement)
+{
+  const char *start;
+  char *s = eval_info->exp_buf;
+  struct gdbarch *gdbarch = eval_info->gdbarch;
+  struct frame_info *frame = eval_info->frame;
+  enum stap_arg_bitness bitness = eval_info->bitness;
+  char *regname;
+  int len, regnum, indirect_p = 0;
+  struct value *ret = NULL;
+  
+  /* The function which called us did not check if the expression
+     buffer was empty.  */
+  gdb_assert (s && *s);
+
+  if (eval_info->compiling_p)
+    /* If we are compiling, we cannot return NULL because that would
+       lead to errors in future evaluations.  That's why we just make
+       this dummy value, representing that the return value of this
+       function is not NULL.  */
+    ret = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
+
+  /* Valid register name on x86 platforms are:
+
+     [paren]%{a-z0-9}[paren]
+
+     Let's check for that here.  */
+  if (*s == '(')
+    {
+      ++s;
+      if (!*s || *s != '%'
+	  || (*s == '%' && !isalpha (s[1])))
+	error (_("Invalid register name on expression `%s'."),
+	       eval_info->saved_expr);
+      ++s;
+      /* The presence of parenthesis means that we want to indirect
+	 the register.  */
+      indirect_p = 1;
+    }
+  else if (*s == '%')
+    {
+      ++s;
+      if (!*s || !isalpha (*s))
+	error (_("Invalid register name on expression `%s'."),
+	       eval_info->saved_expr);
+    }
+  else
+    error (_("Invalid register name on expression `%s'."),
+	   eval_info->saved_expr);
+
+  if (displacement && !indirect_p)
+    /* We cannot apply displacement to non-indirect register access.  */
+    error (_("Trying to apply displacement without indirecting register "
+	     "on expression `%s'."), eval_info->saved_expr);
+
+  /* Ok, let's calculate the size of the register name.  */
+  start = s;
+  while (isalnum (*s))
+    ++s;
+
+  len = s - start;
+
+  if (indirect_p && *s == ')')
+    ++s;
+
+  regname = alloca (len + 1);
+  strncpy (regname, start, len);
+  regname[len] = '\0';
+
+  /* Translating the register name into the corresponding number.  */
+  regnum = user_reg_map_name_to_regnum (gdbarch, regname, len);
+
+  if (regnum == -1)
+    error (_("Invalid register name `%s' on expression `%s'."),
+	   regname, eval_info->saved_expr);
+
+  if (eval_info->compiling_p)
+    ax_reg (eval_info->aexpr, regnum);
+  else
+    ret = value_of_register (regnum, frame);
+
+  if (indirect_p)
+    {
+      struct type *t = NULL;
+      enum agent_op aop = aop_ref32;
+
+      /* If the user has specified that the register must be indirected,
+	 we should know what's the correct type to cast it before making
+	 the indirection.  This type corresponds to the bitness specified
+	 before the `@' sign on the argument string, or it defaults to
+	 `unsigned long' if the `@' were not present.  */
+
+      switch (bitness)
+	{
+	case STAP_ARG_BITNESS_UNDEFINED:
+	  if (eval_info->compiling_p)
+	    {
+	      if (gdbarch_addr_bit (gdbarch) == 32)
+		aop = aop_ref32;
+	      else
+		aop = aop_ref64;
+	    }
+	  else
+	    {
+	      if (gdbarch_addr_bit (gdbarch) == 32)
+		t = lookup_pointer_type
+		  (builtin_type (gdbarch)->builtin_uint32);
+	      else
+		t = lookup_pointer_type
+		  (builtin_type (gdbarch)->builtin_uint64);
+	    }
+	  break;
+
+	case STAP_ARG_BITNESS_32BIT_SIGNED:
+	  if (eval_info->compiling_p)
+	    aop = aop_ref32;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_int32);
+	  break;
+
+	case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+	  if (eval_info->compiling_p)
+	    aop = aop_ref32;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_uint32);
+	  break;
+
+	case STAP_ARG_BITNESS_64BIT_SIGNED:
+	  if (eval_info->compiling_p)
+	    aop = aop_ref64;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_int64);
+	  break;
+
+	case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+	  if (eval_info->compiling_p)
+	    aop = aop_ref64;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_uint64);
+	  break;
+
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("Undefined bitness for probe."));
+	  break;
+	}
+
+      if (displacement)
+	{
+	  if (eval_info->compiling_p)
+	    {
+	      ax_const_l (eval_info->aexpr, value_as_long (displacement));
+	      ax_simple (eval_info->aexpr, aop_add);
+	    }
+	  else
+	    ret = value_ptradd (ret, value_as_long (displacement));
+	}
+
+      if (eval_info->compiling_p)
+	{
+	  if (trace_kludge)
+	    {
+	      gdb_assert (aop == aop_ref32 || aop == aop_ref64);
+	      ax_trace_quick (eval_info->aexpr, aop == aop_ref32 ? 4 : 8);
+	    }
+	  ax_simple (eval_info->aexpr, aop);
+	}
+      else
+	{
+	  ret = value_cast (t, ret);
+	  ret = value_ind (ret);
+	}
+    }
+
+  /* Updating the expression buffer pointer, because we have made
+     some modifications to it before.  */
+  eval_info->exp_buf = s;
+
+  return ret;
+}
+
+/* This function tries to evaluate a single operand of the expression.
+
+   Single operands can be:
+
+   - unary operators `-' and `~';
+   - integer constants (beginning with `$');
+   - register access, with/out displacement and indirection.  */
+
+static struct value *
+stap_evaluate_single_operand (struct stap_evaluation_info *eval_info)
+{
+  struct gdbarch *gdbarch = eval_info->gdbarch;
+  struct frame_info *frame = eval_info->frame;
+  enum stap_arg_bitness bitness = eval_info->bitness;
+  struct value *res = NULL;
+
+  if (eval_info->compiling_p)
+    /* If we are compiling, we cannot return NULL because that would
+       lead to errors in future evaluations.  That's why we just make
+       this dummy value, representing that the return value of this
+       function is not NULL.  */
+    res = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
+
+  switch (*eval_info->exp_buf)
+    {
+    case '-': case '~':
+	{
+	  char c = *eval_info->exp_buf;
+
+	  /* This is an unary operator (either `-' or `~').
+
+	     If it is followed by a parenthesis, and this parenthesis
+	     is NOT followed by a `%', then we are dealing with an expression
+	     like `-(2 + 3)' or `~(2 + 3)'.  We just have to treat separately
+	     and return the result after applying the operation (`-' or `~').
+
+	     If it is followed by a digit, then we have only one choice:  it
+	     is a displacement argument for a register access, like
+	     `-4(%eax)'.  It also means that the operator can *only* be `-',
+	     and the characters immediately after the number *must* be `(%'.
+
+	     If it is followed by a `$', then it is an integer constant, and
+	     we should apply the correct operation to it.  */
+
+	  ++eval_info->exp_buf;
+	  eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+	  if (*eval_info->exp_buf
+	      && *eval_info->exp_buf == '('
+	      && eval_info->exp_buf[1] != '%')
+	    {
+	      struct value *tmp_res;
+
+	      /* We're not dealing with a register name, but with an
+		 expression like `-(2 + 3)' or `~(2 + 3)'.  We first have
+		 to evaluate the right side of the expression (i.e., the
+		 parenthesis), and then apply the specified operation
+		 (either `-' or `~') to it.  */
+	      tmp_res = stap_evaluate_conditionally (eval_info);
+
+	      if (c == '-')
+		{
+		  if (eval_info->compiling_p)
+		    {
+		      /* We have to add `-1' to the stack, and multiply
+			 the two values.  */
+		      ax_const_l (eval_info->aexpr, -1);
+		      ax_simple (eval_info->aexpr, aop_mul);
+		    }
+		  else
+		    res = value_neg (tmp_res);
+		}
+	      else
+		{
+		  if (eval_info->compiling_p)
+		    ax_simple (eval_info->aexpr, aop_bit_not);
+		  else
+		    res = value_complement (tmp_res);
+		}
+	    }
+	  else if (isdigit (*eval_info->exp_buf))
+	    {
+	      int number;
+
+	      /* This is a number, so it MUST be a register displacement.
+		 The only operator allowed here is `-', it MUST be
+		 followed by a number, and the number MUST be followed by
+		 `(%'.  */
+	      if (c != '-')
+		error (_("Invalid operator `%c' for register displacement "
+			 "on expression `%s'."), c, eval_info->saved_expr);
+
+	      number = strtol (eval_info->exp_buf,
+			       &eval_info->exp_buf, 0) * -1;
+
+	      if (!*eval_info->exp_buf
+		  || *eval_info->exp_buf != '('
+		  || (*eval_info->exp_buf == '('
+		      && eval_info->exp_buf[1] != '%'))
+		error (_("Invalid method of indirecting a register on "
+			 "expression `%s'."), eval_info->saved_expr);
+
+	      res
+		= value_from_longest (builtin_type (gdbarch)->builtin_int,
+				      number);
+
+	      res = stap_fetch_reg_value (eval_info, res);
+	    }
+	  else if (*eval_info->exp_buf == '$')
+	    {
+	      int number;
+
+	      /* Last case.  We are dealing with an integer constant, so
+		 we must read it and then apply the necessary operation,
+		 either `-' or `~'.  */
+	      ++eval_info->exp_buf;
+	      number = strtol (eval_info->exp_buf,
+			       &eval_info->exp_buf, 0);
+
+	      if (!eval_info->compiling_p)
+		res
+		  = value_from_longest (builtin_type (gdbarch)->builtin_int,
+					number);
+
+	      if (eval_info->compiling_p)
+		ax_const_l (eval_info->aexpr, number);
+
+	      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+	      if (c == '-')
+		{
+		  if (eval_info->compiling_p)
+		    ax_simple (eval_info->aexpr, aop_log_not);
+		  else
+		    res = value_neg (res);
+		}
+	      else
+		{
+		  if (eval_info->compiling_p)
+		    ax_simple (eval_info->aexpr, aop_bit_not);
+		  else
+		    res = value_complement (res);
+		}
+	    }
+	  else
+	    error (_("Invalid operand to unary operator `%c' on "
+		     "expression `%s'."), c, eval_info->saved_expr);
+	}
+      break;
+
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      {
+	int number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+	/* This is a register displacement with a positive value.  We read
+	   the number, and then check for the mandatory `(%' part.  */
+	if (!*eval_info->exp_buf
+	    || !(*eval_info->exp_buf == '('
+		 && eval_info->exp_buf[1] == '%'))
+	  error (_("Invalid register access on expression `%s'."),
+		 eval_info->saved_expr);
+
+	res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				  number);
+
+	res = stap_fetch_reg_value (eval_info, res);
+      }
+    break;
+
+    case '$':
+      {
+	int number;
+
+	/* This is an integer constant.  We just have to read the number
+	   and return it.  */
+	++eval_info->exp_buf;
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+	number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+	if (eval_info->compiling_p)
+	  ax_const_l (eval_info->aexpr, number);
+	else
+	  res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				    number);
+
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+      }
+    break;
+
+    case '(': case '%':
+      {
+	/* Register access, with or without indirection.  */
+	res = stap_fetch_reg_value (eval_info, /*displacement=*/NULL);
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+      }
+    break;
+
+    default:
+      {
+	error (_("Operator `%c' not recognized on expression `%s'."),
+	       *eval_info->exp_buf, eval_info->saved_expr);
+      }
+    }
+
+  return res;
+}
+
+/* This function is responsible for checking the necessary type of evaluation
+   depending on what is the next "thing" in the buffer.  Valid values are:
+
+   - Unary operators;
+   - Integer constants;
+   - Register displacement, indirection, and direct access;
+   - Parenthesized operand.  */
+
+static struct value *
+stap_evaluate_conditionally (struct stap_evaluation_info *eval_info)
+{
+  char *s = eval_info->exp_buf;
+  struct value *ret = NULL;
+
+  if (*s == '-' || *s == '~' /* Unary operators.  */
+      || *s == '$' /* Number (integer constant).  */
+      || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement.  */
+      || (*s == '(' && s[1] == '%') /* Register indirection.  */
+      || (*s == '%' && isalpha (s[1]))) /* Register value.  */
+    /* This is a single operand, so just evaluate it and return.  */
+    ret = stap_evaluate_single_operand (eval_info);
+  else if (*s == '(')
+    {
+      /* We are dealing with a parenthesized operand.  It means we
+	 have to evaluate it as it was a separate expression, without
+	 left-side or precedence.  */
+      ++eval_info->exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+      ret = stap_evaluate_probe_argument_2 (eval_info,
+					    /*lhs=*/NULL, /*prec=*/0);
+
+      if (*eval_info->exp_buf != ')')
+	error (_("Missign close-paren on expression `%s'."),
+	       eval_info->saved_expr);
+
+      ++eval_info->exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+    }
+  else
+    error (_("Cannot evaluate expression `%s'."),
+	   eval_info->saved_expr);
+
+  return ret;
+}
+
+/* Evaluation function for probe's argument expressions.  LHS represents
+   the left side of the expression, and PREC is the precedence of the
+   last operator identified before calling the function.  */
+
+static struct value *
+stap_evaluate_probe_argument_2 (struct stap_evaluation_info *eval_info,
+				struct value *lhs, int prec)
+{
+  struct value *rhs = NULL;
+  int compiling_p = eval_info->compiling_p;
+
+  /* This is an operator-precedence parser and evaluator.
+
+     We work with left- and right-sides of expressions, and
+     evaluate them depending on the precedence of the operators
+     we find.  */
+
+  eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+  if (!lhs)
+    /* We were called without a left-side, either because this is the
+       first call, or because we were called to evaluate a parenthesized
+       expression.  It doesn't really matter; we have to evaluate the
+       left-side in order to continue the process.  */
+    lhs = stap_evaluate_conditionally (eval_info);
+
+  /* Start to evaluate 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 (eval_info->exp_buf
+	 && *eval_info->exp_buf
+	 && *eval_info->exp_buf != ')')
+    {
+      char *tmp_exp_buf;
+      enum exp_opcode opcode;
+      int cur_prec;
+
+      if (!stap_is_operator (eval_info->exp_buf))
+	error (_("Invalid operator `%c' on expression `%s'."),
+	       *eval_info->exp_buf, eval_info->saved_expr);
+
+      /* 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 = eval_info->exp_buf;
+      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 evaluation process began, it means we should stop evaluating
+	   and return.  */
+	break;
+
+      eval_info->exp_buf = tmp_exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+      /* Evaluate the right-side of the expression.  */
+      rhs = stap_evaluate_conditionally (eval_info);
+
+      /* While we still have operators, try to evaluate another
+	 right-side, but using the current right-side as a left-side.  */
+      while (*eval_info->exp_buf
+	     && stap_is_operator (eval_info->exp_buf))
+	{
+	  enum exp_opcode lookahead_opcode;
+	  int lookahead_prec;
+
+	  /* Saving the current expression buffer position.  The explanation
+	     is the same as above.  */
+	  tmp_exp_buf = eval_info->exp_buf;
+	  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;
+
+	  rhs = stap_evaluate_probe_argument_2 (eval_info,
+						rhs, lookahead_prec);
+	}
+
+      /* Now, "join" both left and right sides into one left-side, using
+	 the specified operator.  */
+      if (compiling_p)
+	stap_opcode_to_ax (eval_info, opcode);
+      else
+	lhs = value_binop (lhs, rhs, opcode);
+    }
+
+  return lhs;
+}
+
+/* This function fills the necessary arguments for the evaluation function
+   to work.  */
+
+static struct value *
+stap_evaluate_probe_argument_1 (struct objfile *objfile,
+				const struct stap_probe *probe,
+				struct frame_info *frame,
+				int n)
+{
+  struct stap_evaluation_info eval_info;
+  char *s = (char *) probe->parsed_args->arg[n].arg_str;
+  struct value *res, *vs[4];
+
+  /* Filling necessary information for evaluation function.  */
+  eval_info.saved_expr = s;
+  eval_info.exp_buf = s;
+  eval_info.gdbarch = get_objfile_arch (objfile);
+  eval_info.frame = frame;
+  eval_info.bitness = probe->parsed_args->arg[n].bitness;
+  /* We are not compiling to an agent expression.  */
+  eval_info.compiling_p = 0;
+  eval_info.aexpr = NULL;
+  eval_info.avalue = NULL;
+
+  res = stap_evaluate_probe_argument_2 (&eval_info,
+					/*lhs=*/NULL, /*prec=*/0);
+
+  if (!res)
+    error (_("Could not evaluate expression `%s'."),
+	   eval_info.saved_expr);
+
+  return res;
+}
+
+/* See definition in stap-probe.h.  */
+
+struct value *
+stap_evaluate_probe_argument (struct objfile *objfile,
+			      const struct stap_probe *probe,
+			      struct frame_info *frame,
+			      int n)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  if (!probe->parsed_args->arg
+      || n >= probe->parsed_args->n_args)
+    return NULL;
+
+  return stap_evaluate_probe_argument_1 (objfile, probe, frame, n);
+}
+
+/* Helper function which compiles the probe's argument N into an
+   agent expression, suitable for using with tracepoints.  */
+
+static void
+stap_compile_to_ax_1 (struct objfile *objfile,
+		      const struct stap_probe *probe,
+		      struct agent_expr *expr,
+		      struct axs_value *value,
+		      int n)
+{
+  struct stap_evaluation_info eval_info;
+  struct gdbarch *gdbarch = expr->gdbarch;
+  char *s = (char *) probe->parsed_args->arg[n].arg_str;
+
+  /* Filling necessary information for evaluation function.  */
+  eval_info.saved_expr = s;
+  eval_info.exp_buf = s;
+  eval_info.gdbarch = expr->gdbarch;
+  eval_info.frame = NULL;
+  eval_info.bitness = probe->parsed_args->arg[n].bitness;
+  /* We are compiling to an agent expression.  */
+  eval_info.compiling_p = 1;
+  eval_info.aexpr = expr;
+  eval_info.avalue = value;
+
+  /* We can always use this kind.  */
+  value->kind = axs_rvalue;
+
+  /* Figuring out the correct type for this axs_value.  */
+  switch (eval_info.bitness)
+    {
+    case STAP_ARG_BITNESS_UNDEFINED:
+      if (gdbarch_addr_bit (gdbarch) == 32)
+	value->type = builtin_type (gdbarch)->builtin_uint32;
+      else
+	value->type = builtin_type (gdbarch)->builtin_uint64;
+      break;
+
+    case STAP_ARG_BITNESS_32BIT_SIGNED:
+      value->type = builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+      value->type = builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case STAP_ARG_BITNESS_64BIT_SIGNED:
+      value->type = builtin_type (gdbarch)->builtin_int64;
+      break;
+
+    case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+      value->type = builtin_type (gdbarch)->builtin_uint64;
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Undefined bitness for probe."));
+      break;
+    }
+
+  stap_evaluate_probe_argument_2 (&eval_info,
+				  /*lhs=*/NULL, /*prec=*/0);
+}
+
+/* See definition in stap-probe.h.  */
+
+void
+stap_compile_to_ax (struct objfile *objfile,
+		    const struct stap_probe *probe,
+		    struct agent_expr *expr,
+		    struct axs_value *value,
+		    int n)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  if (!probe->parsed_args->arg
+      || n >= probe->parsed_args->n_args)
+    return;
+
+  stap_compile_to_ax_1 (objfile, probe, expr, value, n);
+}
+
+struct value *
+stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
+{
+  const struct stap_probe *probe;
+  struct objfile *objfile;
+  int 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,
+								  frame,
+								  n);
+}
+
+/* This function frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+void
+stap_free_parsed_args (struct stap_args_info *parsed_args)
+{
+  int i;
+
+  if (!parsed_args
+      || parsed_args == &dummy_stap_args_info
+      || parsed_args->n_args == 0)
+    return;
+
+  for (i = 0; i < parsed_args->n_args; i++)
+    xfree (parsed_args->arg);
+
+  xfree (parsed_args);
+}
+
+/* A utility structure.  A VEC of these is built when handling "info
+   probes".  */
+
+struct stap_probe_and_objfile
+{
+  /* The probe.  */
+  const struct stap_probe *probe;
+  /* The probe's objfile.  */
+  struct objfile *objfile;
+};
+
+typedef struct stap_probe_and_objfile stap_entry;
+DEF_VEC_O (stap_entry);
+
+/* 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.
+   Each argument is a regexp, or NULL, which matches anything.  */
+
+static VEC (stap_entry) *
+collect_probes (char *objname, char *provider, char *probe)
+{
+  struct objfile *objfile;
+  VEC (stap_entry) *result = NULL;
+  struct cleanup *cleanup;
+  regex_t obj_pat, prov_pat, probe_pat;
+
+  cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
+
+  compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
+  compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
+  compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	stap_entry entry;
+
+	if (provider)
+	  {
+	    if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	if (probe)
+	  {
+	    if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	entry.probe = &probes[i];
+	entry.objfile = objfile;
+	VEC_safe_push (stap_entry, result, &entry);
+      }
+  }
+
+  discard_cleanups (cleanup);
+  return result;
+}
+
+/* A qsort comparison function for stap_entry objects.  */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+  const stap_entry *ea = a;
+  const stap_entry *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);
+}
+
+/* Implementation of the "info probes" command.  */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+  char *provider, *probe = NULL, *objname = NULL;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  VEC (stap_entry) *items;
+  int i, addr_width, any_found;
+  stap_entry *entry;
+
+  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);
+	}
+    }
+
+  items = collect_probes (objname, provider, probe);
+  make_cleanup (VEC_cleanup (stap_entry), &items);
+  make_cleanup_ui_out_table_begin_end (uiout, 5,
+				       VEC_length (stap_entry, items),
+				       "SystemTapProbes");
+
+  if (! VEC_empty (stap_entry, items))
+    qsort (VEC_address (stap_entry, items),
+	   VEC_length (stap_entry, items),
+	   sizeof (stap_entry),
+	   compare_entries);
+
+  addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
+
+  ui_out_table_header (uiout, 10, ui_left, "provider", _("Provider"));
+  ui_out_table_header (uiout, 10, ui_left, "name", _("Name"));
+  ui_out_table_header (uiout, addr_width - 1, ui_left, "addr", _("Where"));
+  ui_out_table_header (uiout, addr_width - 1, ui_left, "semaphore",
+		       _("Semaphore"));
+  ui_out_table_header (uiout, 30, ui_left, "object", _("Object"));
+  ui_out_table_body (uiout);
+
+  for (i = 0; VEC_iterate (stap_entry, items, i, entry); ++i)
+    {
+      struct cleanup *inner;
+
+      inner = make_cleanup_ui_out_tuple_begin_end (uiout, "probe");
+
+      ui_out_field_string (uiout, "provider", entry->probe->provider);
+      ui_out_field_string (uiout, "name", entry->probe->name);
+      ui_out_field_core_addr (uiout, "addr", get_current_arch (),
+			      entry->probe->address);
+      if (entry->probe->sem_addr == 0)
+	ui_out_field_skip (uiout, "semaphore");
+      else
+      ui_out_field_core_addr (uiout, "semaphore", get_current_arch (),
+			      entry->probe->sem_addr);
+      ui_out_field_string (uiout, "object", entry->objfile->name);
+      ui_out_text (uiout, "\n");
+
+      do_cleanups (inner);
+    }
+
+  any_found = ! VEC_empty (stap_entry, items);
+  do_cleanups (cleanup);
+
+  if (! any_found)
+    ui_out_message (uiout, 0, _("No probes matched.\n"));
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+const struct stap_probe *
+find_probe_in_objfile (struct objfile *objfile,
+		       const char *provider,
+		       const char *name)
+{
+  const struct stap_probe *probes;
+  int i, num_probes;
+
+  if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+    return NULL;
+
+  probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+  for (i = 0; i < num_probes; ++i)
+    {
+      if (strcmp (probes[i].provider, provider) != 0)
+	continue;
+
+      if (strcmp (probes[i].name, name) != 0)
+	continue;
+
+      return &probes[i];
+    }
+
+  return NULL;
+}
+
+/* See definition in stap-probe.h.  */
+
+struct symtabs_and_lines
+parse_stap_probe (char **argptr, struct linespec_result *canonical,
+		  int *not_found_ptr)
+{
+  char *full_arg = extract_arg (argptr);
+  char *arg = xstrdup (full_arg);
+  char *objfile_name = NULL, *provider = NULL, *name, *p;
+  struct cleanup *cleanup;
+  struct symtabs_and_lines result;
+  struct objfile *objfile;
+
+  result.sals = NULL;
+  result.nelts = 0;
+
+  /* The caller ensured that this starts with 'probe:'.  */
+  gdb_assert (arg && strncmp (arg, "probe:", 6) == 0);
+  cleanup = make_cleanup (xfree, arg);
+  make_cleanup (xfree, full_arg);
+  arg += 6;
+
+  /* Extract each word from the argument, separated by ":"s.  */
+  p = strchr (arg, ':');
+  if (p == NULL)
+    {
+      /* This is `probe:name'.  */
+      name = arg;
+    }
+  else
+    {
+      char *hold = p + 1;
+
+      *p = '\0';
+      p = strchr (hold, ':');
+      if (p == NULL)
+	{
+	  /* This is `probe:provider:name'.  */
+	  provider = arg;
+	  name = hold;
+	}
+      else
+	{
+	  /* This is `probe: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"));
+
+  if (canonical)
+    canonical->canonical = NULL;
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+
+    if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+      continue;
+
+    if (objfile_name
+	&& FILENAME_CMP (objfile->name, objfile_name) != 0
+	&& FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+      continue;
+
+    probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	struct symtab_and_line *sal;
+
+	if (provider && strcmp (probes[i].provider, provider) != 0)
+	  continue;
+
+	if (strcmp (probes[i].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 = probes[i].address;
+	sal->explicit_pc = 1;
+	sal->section = find_pc_overlay (sal->pc);
+	sal->pspace = current_program_space;
+	sal->semaphore = probes[i].sem_addr;
+
+	if (canonical)
+	  {
+	    canonical->canonical = xrealloc (canonical->canonical,
+					     result.nelts * sizeof (char **));
+	    canonical->canonical[result.nelts - 1] = xstrdup (full_arg);
+	  }
+      }
+  }
+
+  if (result.nelts == 0)
+    {
+      if (not_found_ptr)
+	*not_found_ptr = 1;
+      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;
+    }
+
+  do_cleanups (cleanup);
+
+  return result;
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+const struct stap_probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+    stap_entry entry;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	if (probes[i].address == pc)
+	  {
+	    *objfile_out = objfile;
+	    return &probes[i];
+	  }
+      }
+  }
+
+  return NULL;
+}
+
+/* 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;
+  const struct stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL==10 means "_probe_argc".  */
+  gdb_assert (sel >= 0 && sel <= 10);
+
+  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 == 10)
+    return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
+
+  gdb_assert (sel >= 0);
+  if (sel >= n_probes)
+    error (_("Invalid probe argument %d -- probe has %d arguments available"),
+	   sel, n_probes);
+
+  return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+								  pc_probe,
+								  frame, 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;
+  const struct stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL==10 means "_probe_argc".  */
+  gdb_assert (sel >= 0 && sel <= 10);
+
+  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 == 10)
+    {
+      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
+
+/* Implementation of `$_probe_arg*' set of variables.  */
+
+static const struct internalvar_funcs probe_funcs =
+{
+  compute_probe_arg,
+  compile_probe_arg,
+  NULL
+};
+
+void
+_initialize_stap_probe (void)
+{
+  add_info ("probes", info_probes_command, _("\
+Show available static probes.\n\
+Usage: info probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT match the executable or shared library name."));
+
+  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
+				(void *) (uintptr_t) 10);
+  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);
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..5b38399
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,110 @@
+/* SystemTap probe support for GDB.
+
+   Copyright (C) 2011 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
+
+struct stap_args_info;
+struct axs_value;
+struct linespec_result;
+
+/* Main structure which holds information about a SystemTap probe.  */
+
+struct stap_probe
+{
+  /* The provider of this probe.  */
+  const char *provider;
+
+  /* The name of the probe.  */
+  const char *name;
+
+  /* The address where the probe is inserted.  */
+  CORE_ADDR address;
+
+  /* The address of the probe's semaphore, or 0 if this probe does not
+     have an associated semaphore.  */
+  CORE_ADDR sem_addr;
+
+  /* Probe's arguments.  Users should generally not examine this, but
+     should instead extract information about the arguments using the
+     methods provided in sym_probe_fns.  */
+  const char *args;
+
+  /* Probe's arguments after parsing.  This is an opaque structure that
+     will hold information about the arguments pointed by ARGS.  */
+  struct stap_args_info *parsed_args;
+};
+
+
+/* A helper for linespec that decodes a stap probe specification.  It
+   returns a symtabs_and_lines object and updates *ARGPTR or throws an
+   error.  */
+
+extern struct symtabs_and_lines parse_stap_probe (char **argptr,
+						  struct linespec_result *canon,
+						  int *not_found_ptr);
+
+/* Search OBJFILE for a probe with the given PROVIDER and NAME.  If a
+   probe is found, return it.  If no probe is found, return NULL.  */
+
+extern const struct stap_probe *find_probe_in_objfile (struct objfile *objfile,
+						       const char *provider,
+						       const char *name);
+
+/* Given a PC, find an associated SystemTap probe.  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 const struct stap_probe *find_probe_by_pc (CORE_ADDR pc,
+						  struct objfile **objfile_out);
+
+/* Given PROBE, returns the number of arguments present in that probe's
+   argument string.  */
+
+extern int stap_get_probe_argument_count (const struct stap_probe *probe);
+
+/* Given PARSED_ARGS, frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+extern void stap_free_parsed_args (struct stap_args_info *parsed_args);
+
+/* Evaluates the probe's argument N, returning a value corresponding
+   to it.  */
+
+extern struct value *stap_evaluate_probe_argument (struct objfile *objfile,
+						   const struct stap_probe *probe,
+						   struct frame_info *frame,
+						   int n);
+
+/* Compile the probe's argument N to agent expression.  */
+
+extern void stap_compile_to_ax (struct objfile *objfile,
+				const struct stap_probe *probe,
+				struct agent_expr *expr,
+				struct axs_value *value,
+				int n);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+   evaluates argument N.  If there is no probe at that location, or if
+   the probe does not have enough arguments, this returns NULL.  */
+
+extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
+					       int n);
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index a0151ea..752c46a 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -31,6 +31,11 @@ struct objfile;
 struct obj_section;
 struct obstack;
 struct block;
+struct stap_probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
 
 /* Comparison function for symbol look ups.  */
 
@@ -296,6 +301,52 @@ struct quick_symbol_functions
 				void *data);
 };
 
+/* Structure of functions used for SystemTap probe support.  If one of
+   these functions is provided, all must be.  */
+
+struct sym_probe_fns
+{
+  /* If non-NULL, return an array of SystemTap probe objects.  The
+     number of objects is returned in *NUM_PROBES.  */
+  const struct stap_probe *(*sym_get_probes) (struct objfile *,
+					      int *num_probes);
+
+  /* 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.  */
+  int (*sym_get_probe_argument_count) (struct objfile *objfile,
+				       const struct stap_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,
+						const struct stap_probe *probe,
+						struct frame_info *frame,
+						int 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,
+			     const struct stap_probe *probe,
+			     struct agent_expr *expr,
+			     struct axs_value *value,
+			     int 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.  */
 
@@ -366,6 +417,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 8aa692d..0bcbbf7 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -770,6 +770,7 @@ init_sal (struct symtab_and_line *sal)
   sal->end = 0;
   sal->explicit_pc = 0;
   sal->explicit_line = 0;
+  sal->semaphore = 0;
 }
 \f
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index abe5e86..6239f7f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1109,6 +1109,10 @@ struct symtab_and_line
   CORE_ADDR end;
   int explicit_pc;
   int explicit_line;
+
+  /* If non-zero, the semaphore location associated with a SystemTap
+     probe.  */
+  CORE_ADDR semaphore;
 };
 
 extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9723a04..7fd06f3 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2011-04-03  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.cp/nextoverthrow.exp: Add check for SystemTap probe in
+	libgcc's unwinder.
+	* gdb.trace/stap-trace.c: New file.
+	* gdb.trace/stap-trace.exp: New file.
+
 2011-04-01  Joel Brobecker  <brobecker@adacore.com>
 
 	* gdb.ada/arrayptr/foo.adb: Add access to constrained array.
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index d58c519..abb1b05 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -607,6 +607,17 @@ 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>} \
     }
 
 #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..47e4b39
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,69 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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 teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_two_semaphore
+
+#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
+
+void
+m1 (void)
+{
+  if (TEST2)
+    STAP_PROBE (teste, two);
+}
+
+void
+m2 (void)
+{
+  if (TEST2)
+    STAP_PROBE (teste, two);
+}
+
+int
+f (int x)
+{
+  if (TEST)
+    STAP_PROBE1(teste, user, x);
+  return x+5;
+}
+
+int
+main()
+{
+  f(f(23));
+  m1();
+  m2();
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..3fb7377
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,72 @@
+# Copyright (C) 2011 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 {$arg != ""} {
+    	set arg "additional_flags=$arg"
+	set addendum ", with semaphore"
+    } else {
+	set addendum ", no semaphore"
+    }
+
+    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$addendum"
+
+    gdb_test "info probes" \
+	"teste *user *$hex .*" \
+	"info probes$addendum"
+    
+    if {[runto "probe:teste:user"]} {
+	pass "run to probe:teste:user$addendum"
+    } else {
+	fail "run to probe:teste:user$addendum"
+    }
+
+    # Test probe arguments.
+    gdb_test "print \$_probe_argc" " = 1" "print \$_probe_argc$addendum"
+    gdb_test "print \$_probe_arg0 == x" " = 1" "check \$_probe_arg0$addendum"
+    gdb_test "print \$_probe_arg1" \
+    	"Invalid probe argument 1 -- probe has 1 arguments available" \
+    	"check \$_probe_arg1$addendum"
+
+    # Set a breakpoint with multiple probe locations.
+    gdb_test "break probe:teste:two" \
+	"Breakpoint .* at $hex.*2 locations.*" \
+	"set multi-location probe breakpoint$addendum"
+
+    return 0
+}
+
+if {[stap_test] == -1} {
+    untested stap-probe.exp
+    return -1
+}
+stap_test "-DUSE_PROBES"
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 89c02d6..a970bb9 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -53,6 +53,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..27f317e
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.c
@@ -0,0 +1,71 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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 teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_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 (teste, two, x);
+}
+
+int
+f (int x)
+{
+  if (TEST)
+    STAP_PROBE1(teste, 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..189355f
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.exp
@@ -0,0 +1,129 @@
+# Copyright 2011
+# 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"
+
+if $tracelevel then {
+	strace $tracelevel
+}
+
+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:user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "probe:two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 12e1b80..1cb39ea 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -1600,6 +1600,8 @@ start_tracing (void)
 
   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))
@@ -1608,6 +1610,9 @@ start_tracing (void)
       t->number_on_target = 0;
       target_download_tracepoint (t);
       t->number_on_target = t->number;
+
+      for (loc = t->loc; loc; loc = loc->next)
+	modify_semaphore (loc, 1);
     }
   VEC_free (breakpoint_p, tp_vec);
 
@@ -1669,7 +1674,28 @@ trace_stop_command (char *args, int from_tty)
 void
 stop_tracing (void)
 {
+  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)
+	modify_semaphore (loc, 0);
+    }
+
+  VEC_free (breakpoint_p, tp_vec);
+
   /* Should change in response to reply?  */
   current_trace_status ()->running = 0;
 }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 081080c..f71dbfe 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3090,6 +3090,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
 };
 

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-04  3:09 [PATCH 4/6] Implement support for SystemTap probes Sergio Durigan Junior
@ 2011-04-04 19:06 ` Eli Zaretskii
  2011-04-06 20:20 ` Tom Tromey
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 83+ messages in thread
From: Eli Zaretskii @ 2011-04-04 19:06 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, tromey

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Tom Tromey <tromey@redhat.com>
> Date: Mon, 04 Apr 2011 00:08:43 -0300
> 
> This is the biggest patch of the series.  It implements a bunch of new
> functions used to support SystemTap probes (they live in
> `stap-probe.[ch]'), and also modifies internal mechanisms to adapt them
> to this new feature.  The patch also includes testcases, documentation,
> and modifications on the tracepoint code to support collecting probe
> arguments.

Thanks, the doco parts are okay.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-04  3:09 [PATCH 4/6] Implement support for SystemTap probes Sergio Durigan Junior
  2011-04-04 19:06 ` Eli Zaretskii
@ 2011-04-06 20:20 ` Tom Tromey
  2011-04-06 20:52   ` Sergio Durigan Junior
  2011-04-07  2:41 ` Yao Qi
  2011-04-19 16:42 ` Jan Kratochvil
  3 siblings, 1 reply; 83+ messages in thread
From: Tom Tromey @ 2011-04-06 20:20 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:

Sergio> This is the biggest patch of the series.

I noticed a little nit:

Sergio> -2011-04-01  Tom Tromey  <tromey@redhat.com>
Sergio> +2011-04-03  Tom Tromey  <tromey@redhat.com>

... the patch included a spurious ChangeLog diff.

Tom

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-06 20:20 ` Tom Tromey
@ 2011-04-06 20:52   ` Sergio Durigan Junior
  0 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-04-06 20:52 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Tom Tromey <tromey@redhat.com> writes:

>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> This is the biggest patch of the series.
>
> I noticed a little nit:
>
> Sergio> -2011-04-01  Tom Tromey  <tromey@redhat.com>
> Sergio> +2011-04-03  Tom Tromey  <tromey@redhat.com>
>
> ... the patch included a spurious ChangeLog diff.

Oh yeah, you're right, thanks!  I will fix this when the patch is
approved.

Thanks,

Sergio.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-04  3:09 [PATCH 4/6] Implement support for SystemTap probes Sergio Durigan Junior
  2011-04-04 19:06 ` Eli Zaretskii
  2011-04-06 20:20 ` Tom Tromey
@ 2011-04-07  2:41 ` Yao Qi
  2011-04-07  3:32   ` Sergio Durigan Junior
                     ` (2 more replies)
  2011-04-19 16:42 ` Jan Kratochvil
  3 siblings, 3 replies; 83+ messages in thread
From: Yao Qi @ 2011-04-07  2:41 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey

On 04/04/2011 11:08 AM, Sergio Durigan Junior wrote:

Code looks pretty good!  Thanks.  Some small cents....

> +struct stap_evaluation_info
> +{
....
....
> +
> +  /* Flag to indicate if we are compiling an agent expression.  */
> +  int compiling_p;
> +
> +  /* If the above flag is true (one), this field will contain the
> +     pointer to the agent expression.  */
> +  struct agent_expr *aexpr;

Field `compiling_p' looks redundant to me.  We can use field `aexpr'
directly.  Maybe, we can create a macro

#define COMPILING_AGENT_EXPR_P(eval_info) (eval_info->aexpr != NULL)

> +
> +  /* The value we are modifying (for agent expression).  */
> +  struct axs_value *avalue;
> +};

> +/* Helper function which is responsible for freeing the space allocated to
> +   hold information about a probe's arguments.  */
> +
> +static void
> +stap_free_args_info (void *args_info_ptr)
> +{
> +  struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
> +  int i;
> +
> +  for (i = 0; i < STAP_MAX_ARGS; i++)
> +    {
> +      xfree (a->arg->arg_str);

                   ^^^^
I guess it should be `a->arg[i].arg_str.

> +    }
> +
> +  xfree (a->arg);
> +  xfree (a);
> +}


> +static struct value *
> +stap_evaluate_single_operand (struct stap_evaluation_info *eval_info)
> +{
...
...
> +	    }
> +	  else if (*eval_info->exp_buf == '$')
> +	    {
> +	      int number;
> +
> +	      /* Last case.  We are dealing with an integer constant, so
> +		 we must read it and then apply the necessary operation,
> +		 either `-' or `~'.  */
> +	      ++eval_info->exp_buf;
> +	      number = strtol (eval_info->exp_buf,
> +			       &eval_info->exp_buf, 0);
> +
> +	      if (!eval_info->compiling_p)
> +		res
> +		  = value_from_longest (builtin_type (gdbarch)->builtin_int,
> +					number);
> +
> +	      if (eval_info->compiling_p)
> +		ax_const_l (eval_info->aexpr, number);

We can use if/else to replace these two if statements.


> +/* 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;
> +  const struct stap_probe *pc_probe;
> +  int n_probes;
> +
> +  /* SEL==10 means "_probe_argc".  */
> +  gdb_assert (sel >= 0 && sel <= 10);

Comment here is good, but `10' is still like a `magic number'.  We may
use STAP_MAX_ARGS directly here.

> +
> +  pc_probe = find_probe_by_pc (pc, &objfile);

I don't understand this part.  We are looking for probe by matching
frame's PC here, but address of stap_probe is the address where the
probe is inserted.  So, probably, we can't find any probe here, is that
correct?

> +  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 == 10)
> +    return value_from_longest (builtin_type (arch)->builtin_int,
n_probes);
> +
> +  gdb_assert (sel >= 0);

This check is redundant, because of another check in several lines
before `gdb_assert (sel >= 0 && sel <= 10);'.  We can remove it.

This function looks quite similar to `stap_safe_evaluate_at_pc', some
code in these two functions are duplicated.  We can merge them together.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-07  2:41 ` Yao Qi
@ 2011-04-07  3:32   ` Sergio Durigan Junior
  2011-04-07 17:04   ` Tom Tromey
  2011-04-08 12:38   ` Sergio Durigan Junior
  2 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-04-07  3:32 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches, Tom Tromey

Hi Yao,

Thanks for the review.  I'll answer it quickly now, will take a look
deeper later, and re-submit the patch too.

Yao Qi <yao@codesourcery.com> writes:

> On 04/04/2011 11:08 AM, Sergio Durigan Junior wrote:
>
> Code looks pretty good!  Thanks.  Some small cents....
>
>> +struct stap_evaluation_info
>> +{
> ....
> ....
>> +
>> +  /* Flag to indicate if we are compiling an agent expression.  */
>> +  int compiling_p;
>> +
>> +  /* If the above flag is true (one), this field will contain the
>> +     pointer to the agent expression.  */
>> +  struct agent_expr *aexpr;
>
> Field `compiling_p' looks redundant to me.  We can use field `aexpr'
> directly.  Maybe, we can create a macro
>
> #define COMPILING_AGENT_EXPR_P(eval_info) (eval_info->aexpr != NULL)

Ok, no problem for me.  I thought that maybe a flag would be easier to
understand, but I don't see any drawbacks in adopting the #define.

>> +
>> +  /* The value we are modifying (for agent expression).  */
>> +  struct axs_value *avalue;
>> +};
>
>> +/* Helper function which is responsible for freeing the space allocated to
>> +   hold information about a probe's arguments.  */
>> +
>> +static void
>> +stap_free_args_info (void *args_info_ptr)
>> +{
>> +  struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
>> +  int i;
>> +
>> +  for (i = 0; i < STAP_MAX_ARGS; i++)
>> +    {
>> +      xfree (a->arg->arg_str);
>
>                    ^^^^
> I guess it should be `a->arg[i].arg_str.

You are right.

>> +static struct value *
>> +stap_evaluate_single_operand (struct stap_evaluation_info *eval_info)
>> +{
> ...
> ...
>> +	    }
>> +	  else if (*eval_info->exp_buf == '$')
>> +	    {
>> +	      int number;
>> +
>> +	      /* Last case.  We are dealing with an integer constant, so
>> +		 we must read it and then apply the necessary operation,
>> +		 either `-' or `~'.  */
>> +	      ++eval_info->exp_buf;
>> +	      number = strtol (eval_info->exp_buf,
>> +			       &eval_info->exp_buf, 0);
>> +
>> +	      if (!eval_info->compiling_p)
>> +		res
>> +		  = value_from_longest (builtin_type (gdbarch)->builtin_int,
>> +					number);
>> +
>> +	      if (eval_info->compiling_p)
>> +		ax_const_l (eval_info->aexpr, number);
>
> We can use if/else to replace these two if statements.

You are right.

>> +/* 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;
>> +  const struct stap_probe *pc_probe;
>> +  int n_probes;
>> +
>> +  /* SEL==10 means "_probe_argc".  */
>> +  gdb_assert (sel >= 0 && sel <= 10);
>
> Comment here is good, but `10' is still like a `magic number'.  We may
> use STAP_MAX_ARGS directly here.

Ok, makes sense.

>> +
>> +  pc_probe = find_probe_by_pc (pc, &objfile);
>
> I don't understand this part.  We are looking for probe by matching
> frame's PC here, but address of stap_probe is the address where the
> probe is inserted.  So, probably, we can't find any probe here, is that
> correct?

Sorry, I'm not sure I understood your question.  Maybe I'll leave it for
Tom to answer.

>> +  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 == 10)
>> +    return value_from_longest (builtin_type (arch)->builtin_int,
> n_probes);
>> +
>> +  gdb_assert (sel >= 0);
>
> This check is redundant, because of another check in several lines
> before `gdb_assert (sel >= 0 && sel <= 10);'.  We can remove it.

Makes sense.

> This function looks quite similar to `stap_safe_evaluate_at_pc', some
> code in these two functions are duplicated.  We can merge them together.

Ok, I'll take a look at this ASAP.

Thanks for the review again!

Sergio.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-07  2:41 ` Yao Qi
  2011-04-07  3:32   ` Sergio Durigan Junior
@ 2011-04-07 17:04   ` Tom Tromey
  2011-04-11  3:21     ` Yao Qi
  2011-04-08 12:38   ` Sergio Durigan Junior
  2 siblings, 1 reply; 83+ messages in thread
From: Tom Tromey @ 2011-04-07 17:04 UTC (permalink / raw)
  To: Yao Qi; +Cc: Sergio Durigan Junior, gdb-patches

>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:

>> +  pc_probe = find_probe_by_pc (pc, &objfile);

Yao> I don't understand this part.  We are looking for probe by matching
Yao> frame's PC here, but address of stap_probe is the address where the
Yao> probe is inserted.  So, probably, we can't find any probe here, is that
Yao> correct?

I believe that the frame PC here actually is the location of the probe.
Is there a situation where this would not be the case?

stap-probe.exp specifically checks this code, by evaluating probe
arguments at a probe point.

Tom

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-07  2:41 ` Yao Qi
  2011-04-07  3:32   ` Sergio Durigan Junior
  2011-04-07 17:04   ` Tom Tromey
@ 2011-04-08 12:38   ` Sergio Durigan Junior
  2011-04-11  3:52     ` Yao Qi
  2011-08-12 15:45     ` Jan Kratochvil
  2 siblings, 2 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-04-08 12:38 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches, Tom Tromey

Yao Qi <yao@codesourcery.com> writes:

> On 04/04/2011 11:08 AM, Sergio Durigan Junior wrote:
>
> Code looks pretty good!  Thanks.  Some small cents....

Ok, so here is the updated version of the patch.  Please tell me what
you think.

Thanks,

Sergio.

---
 gdb/ChangeLog                          |   58 +
 gdb/Makefile.in                        |    8 +-
 gdb/NEWS                               |    4 +
 gdb/breakpoint.c                       |   43 +
 gdb/breakpoint.h                       |   12 +
 gdb/cli/cli-utils.c                    |   29 +
 gdb/cli/cli-utils.h                    |    7 +
 gdb/coffread.c                         |    1 +
 gdb/dbxread.c                          |    3 +-
 gdb/doc/ChangeLog                      |    4 +
 gdb/doc/gdb.texinfo                    |   82 ++
 gdb/elfread.c                          |  281 +++++
 gdb/linespec.c                         |    5 +
 gdb/machoread.c                        |    1 +
 gdb/mipsread.c                         |    1 +
 gdb/objfiles.c                         |    5 +
 gdb/somread.c                          |    1 +
 gdb/stap-probe.c                       | 2041 ++++++++++++++++++++++++++++++++
 gdb/stap-probe.h                       |  109 ++
 gdb/symfile.h                          |   55 +
 gdb/symtab.c                           |    1 +
 gdb/symtab.h                           |    4 +
 gdb/testsuite/ChangeLog                |   12 +
 gdb/testsuite/gdb.base/default.exp     |   11 +
 gdb/testsuite/gdb.base/stap-probe.c    |   69 ++
 gdb/testsuite/gdb.base/stap-probe.exp  |   72 ++
 gdb/testsuite/gdb.cp/nextoverthrow.exp |   11 +
 gdb/testsuite/gdb.trace/stap-trace.c   |   71 ++
 gdb/testsuite/gdb.trace/stap-trace.exp |  129 ++
 gdb/tracepoint.c                       |   26 +
 gdb/xcoffread.c                        |    1 +
 31 files changed, 3152 insertions(+), 5 deletions(-)
 create mode 100644 gdb/stap-probe.c
 create mode 100644 gdb/stap-probe.h
 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/ChangeLog b/gdb/ChangeLog
index 67ec955..5f0b9ce 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,61 @@
+2011-04-08  Sergio Durigan Junior  <sergiodj@redhat.com>
+	    Tom Tromey  <tromey@redhat.com>
+
+	* Makefile.in (SFILES): Add `stap-probe'.
+	(COMMON_OBS): Likewise.
+	(HFILES_NO_SRCDIR): Likewise.
+	* NEWS: Mention support for SystemTap probes.
+	* breakpoint.c: Include `gdb_regex.h' and `stap-probe.h'.
+	(modify_semaphore): New function.
+	(insert_bp_location): Call `modify_semaphore'.
+	(remove_breakpoint_1): Likewise.
+	(set_raw_breakpoint): Use the `semaphore' value.
+	(clone_momentary_breakpoint): Likewise.
+	(add_location_to_breakpoint): Likewise.
+	* breakpoint.h (struct bp_location) <semaphore>: New field.
+	(modify_semaphore): New function.
+	* cli/cli-utils.c (extract_arg): New function.
+	* cli/cli-utils.h (extract_arg): Likewise.
+	* coffread.c (coff_sym_fns): Add `sym_probe_fns' value.
+	* dbxread.c (aout_sym_fns): Likewise.
+	* elfread.c: Include `stap-probe.h' and `arch-utils.h'.
+	(stap_probe_key): New variable.
+	(struct stap_probe_per_objfile): New struct.
+	(handle_probe): New function.
+	(STAP_BASE_SECTION_NAME): New define.
+	(get_base_address_1): New function.
+	(get_base_address): Likewise.
+	(elf_get_probes): Likewise.
+	(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 SystemTap
+	probes.
+	* linespec.c (keep_name_info): Update comment in order to add the
+	`probe:' syntax.
+	(decode_line_1): Handle the `probe:' syntax.
+	* machoread.c (macho_sym_fns): Add `sym_probe_fns' value.
+	* mipsread.c (ecoff_sym_fns): Likewise.
+	* objfiles.c (objfile_relocate1): Support relocation for SystemTap
+	probes.
+	* 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 (struct sym_probe_fns): New struct.
+	(struct sym_fns) <sym_probe_fns>: New field.
+	* symtab.c (init_sal): Initialize `semaphore' field.
+	* symtab.h (struct symtab_and_line) <semaphore>: New field.
+	* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
+	locations.
+	(trace_stop_command): Likewise.
+	* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
+
 2011-04-08  Tom Tromey  <tromey@redhat.com>
 
 	* ax-gdb.c (gen_expr): Clean up code to handle internal variables
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6abd87a..8f8e7fc 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -721,8 +721,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 \
 	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 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 \
@@ -814,7 +814,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
-gnulib/stddef.in.h inline-frame.h
+gnulib/stddef.in.h inline-frame.h stap-probe.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -899,7 +899,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	prologue-value.o memory-map.o memrange.o xml-support.o xml-syscall.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
+	jit.o progspace.o stap-probe.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/NEWS b/gdb/NEWS
index a673d7a..2b87274 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -38,6 +38,10 @@
   Initial support for the OpenCL C language (http://www.khronos.org/opencl)
   has been integrated into GDB.
 
+* GDB now has support for SystemTap <sys/sdt.h> probes.  You can set a
+  breakpoint using the new "probe:" linespec and inspect the probe
+  arguments using the new $_probe_arg family of convenience variables.
+
 * Python scripting
 
   ** The function gdb.Write now accepts an optional keyword 'stream'.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1f7100f..3f48faf 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -63,6 +63,8 @@
 #include "jit.h"
 #include "xml-syscall.h"
 #include "parser-defs.h"
+#include "gdb_regex.h"
+#include "stap-probe.h"
 #include "cli/cli-utils.h"
 
 /* readline include files */
@@ -1520,6 +1522,40 @@ should_be_inserted (struct bp_location *bl)
   return 1;
 }
 
+/* See the comment in breakpoint.h.  */
+
+void
+modify_semaphore (struct bp_location *loc, int set)
+{
+  struct gdbarch *arch = loc->gdbarch;
+  gdb_byte bytes[sizeof (LONGEST)];
+  /* The ABI specifies "unsigned short".  */
+  struct type *type = builtin_type (arch)->builtin_unsigned_short;
+  CORE_ADDR address = loc->semaphore;
+  ULONGEST value;
+
+  if (address == 0)
+    return;
+
+  /* Swallow errors.  */
+  if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
+    return;
+
+  value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
+				    gdbarch_byte_order (arch));
+  /* 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 (arch), value);
+
+  target_write_memory (address, bytes, TYPE_LENGTH (type));
+}
+
 /* Insert a low-level "breakpoint" of some type.  BL is the breakpoint
    location.  Any error messages are printed to TMP_ERROR_STREAM; and
    DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
@@ -1616,6 +1652,8 @@ insert_bp_location (struct bp_location *bl,
 	  else
 	    val = target_insert_breakpoint (bl->gdbarch,
 					    &bl->target_info);
+
+	  modify_semaphore (bl, 1);
 	}
       else
 	{
@@ -2553,6 +2591,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
 	    val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
 	  else
 	    val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+
+	  modify_semaphore (bl, 0);
 	}
       else
 	{
@@ -5902,6 +5942,7 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
   b->loc->requested_address = sal.pc;
   b->loc->address = adjusted_address;
   b->loc->pspace = sal.pspace;
+  b->loc->semaphore = sal.semaphore;
 
   /* Store the program space that was used to set the breakpoint, for
      breakpoint resetting.  */
@@ -7049,6 +7090,7 @@ clone_momentary_breakpoint (struct breakpoint *orig)
   copy->loc->address = orig->loc->address;
   copy->loc->section = orig->loc->section;
   copy->loc->pspace = orig->loc->pspace;
+  copy->loc->semaphore = orig->loc->semaphore;
 
   if (orig->source_file == NULL)
     copy->source_file = NULL;
@@ -7272,6 +7314,7 @@ add_location_to_breakpoint (struct breakpoint *b,
   loc->address = adjust_breakpoint_address (loc->gdbarch,
 					    loc->requested_address, b->type);
   loc->pspace = sal->pspace;
+  loc->semaphore = sal->semaphore;
   gdb_assert (loc->pspace != NULL);
   loc->section = sal->section;
 
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..8a91019 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -363,6 +363,11 @@ struct bp_location
      processor's architectual constraints.  */
   CORE_ADDR requested_address;
 
+  /* If the location comes from a SystemTap probe point, and the probe
+     has an associated semaphore variable, then this is the address of
+     the semaphore.  Otherwise, this is zero.  */
+  CORE_ADDR semaphore;
+
   char *function_name;
 
   /* Details of the placed breakpoint, when inserted.  */
@@ -1237,4 +1242,11 @@ extern struct breakpoint *iterate_over_breakpoints (int (*) (struct breakpoint *
 
 extern int user_breakpoint_p (struct breakpoint *);
 
+/* Set or clear a SystemTap semaphore.  LOC is the location which may
+   hold a semaphore.  SET is non-zero if the semaphore should be set,
+   or zero if the semaphore should be cleared.  Semaphores act as
+   reference counters, so calls to this function must be paired.  */
+
+extern void modify_semaphore (struct bp_location *location, int set);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index 62a2f12..dd2824f 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -245,3 +245,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 8a6e5b3..ed1a63e 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -103,4 +103,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 b11dd73..0868a79 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2193,6 +2193,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/dbxread.c b/gdb/dbxread.c
index 51ddd9d..a59ae10 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -1,6 +1,6 @@
 /* Read dbx symbol tables and convert to internal format, for GDB.
    Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
-   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010.
+   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009, 2010, 2011.
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -3587,6 +3587,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/doc/ChangeLog b/gdb/doc/ChangeLog
index 5225a6b..0e66756 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2011-04-08  Tom Tromey  <tromey@redhat.com>
+
+	* gdb.texinfo (Static Probe Points): New entry.
+
 2011-04-02  Joel Brobecker  <brobecker@adacore.com>
 
 	* gdb.texinfo (GDB/MI Output Records): Fix menu entry for
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c71d664..9cb9bb5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3286,6 +3286,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
@@ -4499,6 +4500,50 @@ 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 SystemTap static probe point
+@cindex sdt-probe
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes, using @file{sys/sdt.h}.  @value{GDBN}
+can list the available probes, and you can put breakpoints at the
+probe points (@pxref{Specify Location}).
+
+You can examine the available @code{SystemTap} static probes using
+@code{info probes}:
+
+@table @code
+@kindex info probes
+@item info probes [@var{provider} [@var{name} [@var{objfile}]]]
+List the available @code{SystemTap} static probes.
+
+If given, @var{provider} is a regular expression used to select which
+providers to list.  If omitted, all providers are listed.
+
+If given, @var{name} is a regular expression used to select which
+probes to list.  If omitted, all probes are listed.
+
+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.
+@end table
+
+@vindex $_probe_arg@r{, convenience variable}
+A probe may specify up to ten 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_arg9}.  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.
+
+
 @c  @ifclear BARETARGET
 @node Error in Breakpoints
 @subsection ``Cannot insert breakpoints''
@@ -6414,6 +6459,29 @@ specify the function unambiguously, e.g., if there are several
 functions with identical names in different source files.
 @end table
 
+@cindex SystemTap static probe point
+@item probe:@r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes.  This form of linespec specifies
+the location of such a static probe.  See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on static probes.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable are considered.  If @var{provider} is given, then only
+probes from that provider are considered.
+
+@xref{Static Probe Points}, for more information on finding and using
+static probes.
+
+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:} 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.
+
 @end table
 
 
@@ -8500,6 +8568,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_arg9
+Arguments to a SystemTap static probe.  @xref{Static Probe Points}.
+
 @item $_sdata
 @vindex $_sdata@r{, inspect, convenience variable}
 The variable @code{$_sdata} contains extra collected static tracepoint
@@ -10219,6 +10291,16 @@ Collect all function arguments.
 @item $locals
 Collect all local variables.
 
+@item $_probe_argc
+Collects the number of arguments from the @code{SystemTap} probe at
+which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}
+
+@item $_probe_arg@var{N}
+Where @var{N} varies from 0 to 9.  Collects the @var{N}th argument
+from the @code{SystemTap} probe at which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}
+
 @item $_sdata
 @vindex $_sdata@r{, collect}
 Collect static tracepoint marker specific data.  Only available for
diff --git a/gdb/elfread.c b/gdb/elfread.c
index b9cfa13..a635e0b 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -38,6 +38,8 @@
 #include "demangle.h"
 #include "psympriv.h"
 #include "filenames.h"
+#include "stap-probe.h"
+#include "arch-utils.h"
 #include "gdbtypes.h"
 #include "value.h"
 #include "infcall.h"
@@ -61,6 +63,21 @@ struct elfinfo
     asection *mdebugsect;	/* Section pointer for .mdebug section */
   };
 
+/* Per-objfile data for SystemTap probe info.  */
+
+static const struct objfile_data *stap_probe_key = NULL;
+
+/* Per-objfile data about SystemTap probes.  */
+
+struct stap_probe_per_objfile
+  {
+    /* The number of probes in this objfile.  */
+    int stap_num_probes;
+
+    /* The probes themselves.  */
+    struct stap_probe *probes;
+  };
+
 static void free_elfinfo (void *);
 
 /* Minimal symbols located at the GOT entries for .plt - that is the real
@@ -1551,7 +1568,266 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
     complaint (&symfile_complaints,
 	       _("elf/stab section information missing for %s"), filename);
 }
+
+/* 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.  */
+
+static void
+handle_probe (struct objfile *objfile, struct sdt_note *el,
+	      struct stap_probe *ret, CORE_ADDR base)
+{
+  bfd *abfd = objfile->obfd;
+  int size = bfd_get_arch_size (abfd) / 8;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+  CORE_ADDR base_ref;
+
+  /* Provider and the name of the probe.  */
+  ret->provider = (const char *) &el->data[3 * size];
+  ret->name = memchr (ret->provider, '\0',
+		      (unsigned long *) el->data
+		      + el->size - (unsigned long *) ret->provider);
+  /* Making sure there is a name.  */
+  if (!ret->name)
+    complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+	       objfile->name);
+  else
+    ++ret->name;
+
+  /* Retrieving the probe's address.  */
+  ret->address = extract_typed_address ((const gdb_byte *) &el->data[0],
+					ptr_type);
+  /* Link-time sh_addr of `.stapsdt.base' section.  */
+  base_ref = extract_typed_address ((const gdb_byte *) &el->data[size],
+				    ptr_type);
+  /* Semaphore address.  */
+  ret->sem_addr = extract_typed_address ((const gdb_byte *) &el->data[2 * size],
+					 ptr_type);
+
+  ret->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.  */
+  if (ret->name)
+    {
+      ret->args = memchr (ret->name, '\0',
+			  (unsigned long *) el->data
+			  + el->size - (unsigned long *) ret->name);
+
+      if (ret->args++ != NULL
+	  || memchr (ret->args, '\0', (unsigned long *) el->data
+		     + el->size - (unsigned long *) ret->name)
+	  != el->data + el->size - 1)
+	complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+		   objfile->name);
+    }
+  else
+    ret->args = NULL;
+}
+
+/* The name of the SystemTap section where we will find information about
+   the probes.  */
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
+/* Helper function which tries to find the base address of the SystemTap
+   base section named STAP_BASE_SECTION_NAME.  */
+
+static void
+get_base_address_1 (bfd *abfd, asection *sect, void *obj)
+{
+  bfd_vma *base = (bfd_vma *) obj;
+
+  if (*base == (bfd_vma) -1
+      && (sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
+      && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
+    *base = sect->vma;
+}
+
+/* Helper function which iterates over every section in the BFD file,
+   trying to find the base address of the SystemTap base section.
+   Returns the section address if found, or -1 otherwise.  */
+
+static bfd_vma
+get_base_address (bfd *obfd)
+{
+  bfd_vma base = (bfd_vma) -1;
+
+  bfd_map_over_sections (obfd, get_base_address_1, (void *) &base);
+
+  return base;
+}
+
+/* Implementation of `sym_get_probes', as documented in symfile.h.  */
+
+static const struct stap_probe *
+elf_get_probes (struct objfile *objfile, int *num_probes)
+{
+  struct stap_probe *ret = NULL;
+  struct stap_probe_per_objfile *probes_per_objfile;
+
+  /* Initially, no probes.  */
+  *num_probes = 0;
+
+  /* Have we parsed this objfile's probes already?  */
+  probes_per_objfile
+    = (struct stap_probe_per_objfile *) objfile_data (objfile,
+						      stap_probe_key);
+
+  if (!probes_per_objfile)
+    {
+      /* If we are here, then this is the first time we are parsing the
+	 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 = get_base_address (obfd);
+      struct sdt_note *iter;
+      int i;
+      int n = 0;
+
+      if (! elf_tdata (obfd)->sdt_note_head)
+	/* There isn't any probe here.  */
+	return NULL;
+
+      /* Allocating space for probe info.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head;
+	   iter;
+	   iter = iter->next, ++n);
+
+      ret = xcalloc (n, sizeof (struct stap_probe));
+
+      /* Parsing each probe's information.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
+	   iter;
+	   iter = iter->next, i++)
+	/* We first have to handle all the information about the
+	   probe which is present in the section.  */
+	handle_probe (objfile, iter, &ret[i], base);
+
+      /* Creating a cache for these probes in the objfile's registry.  */
+      probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
+
+      probes_per_objfile->stap_num_probes = n;
+      probes_per_objfile->probes = ret;
+
+      set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
+    }
+  else
+    ret = probes_per_objfile->probes;
+
+  *num_probes = probes_per_objfile->stap_num_probes;
+
+  return ret;
+}
+
+/* Implementation of `sym_get_probe_argument_count', as documented in
+   symfile.h.  */
+
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+			      const struct stap_probe *probe)
+{
+  const char *pargs = probe->args;
+
+  if (!pargs || !*pargs || *pargs == ':')
+    /* No arguments.  */
+    return 0;
+
+  return stap_get_probe_argument_count (probe);
+}
+
+/* Implementation of `sym_evaluate_probe_argument', as documented in
+   symfile.h.  */
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+			     const struct stap_probe *probe,
+			     struct frame_info *frame,
+			     int n)
+{
+  return stap_evaluate_probe_argument (objfile, probe, frame, n);
+}
+
+/* Implementation of `sym_compile_to_ax', as documented in symfile.h.  */
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+		   const struct stap_probe *probe,
+		   struct agent_expr *expr,
+		   struct axs_value *value,
+		   int n)
+{
+  stap_compile_to_ax (objfile, probe, 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 i;
+  struct stap_probe_per_objfile *p
+    = (struct stap_probe_per_objfile *) objfile_data (objfile,
+						      stap_probe_key);
+
+  if (!p)
+    /* No probe to relocate.  */
+    return;
+
+  for (i = 0; i < p->stap_num_probes; i++)
+    {
+      p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      if (p->probes[i].sem_addr)
+	p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
+    }
+}
+
+/* Helper function used to free the space allocated for storing SystemTap
+   probe information.  */
+
+static void
+stap_probe_key_free (struct objfile *objfile, void *d)
+{
+  int i;
+  struct stap_probe_per_objfile *data = (struct stap_probe_per_objfile *) d;
+
+  for (i = 0; i < data->stap_num_probes; i++)
+    stap_free_parsed_args (data->probes[i].parsed_args);
+  xfree (data->probes);
+  xfree (data);
+}
+
 \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 =
@@ -1566,6 +1842,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
 };
 
@@ -1584,6 +1861,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
 };
 
@@ -1601,6 +1879,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
 };
 
@@ -1617,6 +1896,8 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
 void
 _initialize_elfread (void)
 {
+  stap_probe_key
+    = register_objfile_data_with_cleanup (NULL, stap_probe_key_free);
   add_symtab_fns (&elf_sym_fns);
 
   elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 94bb86f..0b76214 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -43,6 +43,7 @@
 #include "arch-utils.h"
 #include <ctype.h>
 #include "cli/cli-utils.h"
+#include "stap-probe.h"
 
 /* We share this one with symtab.c, but it is not exported widely.  */
 
@@ -758,6 +759,7 @@ keep_name_info (char *ptr)
    PC returned is 0.
    FILE:FUNCTION -- likewise, but prefer functions in that file.
    *EXPR -- line in which address EXPR appears.
+   probe:[OBJFILE:][PROVIDER:]NAME -- a systemtap static probe
 
    This may all be followed by an "if EXPR", which we ignore.
 
@@ -824,6 +826,9 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
   if (**argptr == '*')
     return decode_indirect (argptr);
 
+  if (strncmp (*argptr, "probe:", 6) == 0)
+    return parse_stap_probe (argptr, canonical);
+
   is_quoted = (strchr (get_gdb_completer_quote_characters (),
 		       **argptr) != NULL);
 
diff --git a/gdb/machoread.c b/gdb/machoread.c
index dbf9ae4..3db9e16 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -849,6 +849,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 74d795d..7e05317 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -402,6 +402,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 db01f42..2b2798a 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -843,6 +843,11 @@ objfile_relocate1 (struct objfile *objfile,
 				obj_section_addr (s));
     }
 
+  /* Relocating SystemTap 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/somread.c b/gdb/somread.c
index 70831a0..baf68ea 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -439,6 +439,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..836d904
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,2041 @@
+/* SystemTap probe support for GDB.
+
+   Copyright (C) 2011 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 "vec.h"
+#include "ui-out.h"
+#include "gdb_regex.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "filenames.h"
+#include "value.h"
+#include "exceptions.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "user-regs.h"
+#include "complaints.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
+
+#include <ctype.h>
+
+/* This define is used to inform whether we are compiling an agent
+   expression or not.  */
+
+#define STAP_COMPILING_AGENT_EXPR_P(eval_info) \
+  (eval_info->aexpr != NULL)
+
+/* 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 string representing this argument.  */
+  char *arg_str;
+};
+
+/* The maximum number of arguments that a probe can have,
+   as defined in <sys/sdt.h>.  */
+
+#define STAP_MAX_ARGS 10
+
+/* Structure that holds information about all arguments of a probe.  */
+
+struct stap_args_info
+{
+  /* The number of valid parsed arguments.  */
+  int n_args;
+
+  /* The probe to which these arguments belong.  */
+  struct stap_probe *probe;
+
+  /* Information about each argument.  */
+  struct stap_probe_arg *arg;
+};
+
+/* Structure that contains all the necessary information to evaluate
+   an expression.  */
+
+struct stap_evaluation_info
+{
+  /* The constant pointer which holds the expression. This is primarily
+     used for printing error messages.  Evaluation functions should
+     not modify this pointer directly; instead, they should use the
+     EXP_BUFFER pointer below.  */
+  const char *saved_expr;
+
+  /* Modifiable version of the above pointer.  */
+  char *exp_buf;
+
+  /* The pointer to the current gdbarch.  */
+  struct gdbarch *gdbarch;
+
+  /* The pointer to the current frame, used when accessing registers'
+     contents.  */
+  struct frame_info *frame;
+
+  /* The bitness specified for this argument.  */
+  enum stap_arg_bitness bitness;
+
+  /* If the above flag is true (one), this field will contain the
+     pointer to the agent expression.  */
+  struct agent_expr *aexpr;
+
+  /* The value we are modifying (for agent expression).  */
+  struct axs_value *avalue;
+};
+
+/* This dummy variable is used when parsing a probe's argument fails.
+   In this case, the number of arguments for this probe is zero, so that's
+   why this variable is useful.  */
+
+static struct stap_args_info dummy_stap_args_info =
+  { 0, NULL, NULL };
+
+static struct value *stap_evaluate_probe_argument_2
+  (struct stap_evaluation_info *eval_info,
+   struct value *lhs, int prec);
+
+static struct value *stap_evaluate_conditionally
+  (struct stap_evaluation_info *eval_info);
+
+/* Helper function which decides to skip whitespaces or not in a probe's
+   argument string.  Basically, if we are inside a parenthesis expression
+   (i.e., inside a subexpression), we can skip whitespaces; otherwise we
+   cannot.  */
+
+static void
+stap_skip_whitespace_cond (char **s, int inside_paren)
+{
+  if (inside_paren)
+    *s = skip_spaces (*s);
+}
+
+/* Helper function which parses a single argument in a probe's argument
+   string, based on various rules (which can be learned from the `gas'
+   manual).  It returns 1 on success, or 0 otherwise.  */
+
+static int
+stap_parse_arg (const char **p)
+{
+  char *cur = (char *) *p;
+  int done = 0;
+  int paren_open = 0;
+
+  while (!done)
+    {
+      switch (*cur)
+	{
+	case ' ': case 0:
+	  /* If we're here, then we have already parsed everything
+	     from this argument.  */
+	  if (paren_open)
+	    return 0;
+	  done = 1;
+	  break;
+
+	case '(':
+	  ++paren_open;
+	  ++cur;
+	  stap_skip_whitespace_cond (&cur, paren_open);
+	  break;
+
+	case ')':
+	  if (!paren_open)
+	    return 0;
+
+	  --paren_open;
+	  ++cur;
+	  if (paren_open)
+	    cur = skip_spaces (cur);
+	  break;
+
+	case '+': case '-':
+	case '*': case '/':
+	case '>': case '<': case '|': case '&':
+	case '^': case '!':
+	    {
+	      char c = *cur;
+
+	      ++cur;
+	      switch (*cur)
+		{
+		case '>':
+		  if (c != '<' && c != '>')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '<':
+		  if (c != '<')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '=':
+		  if (c != '=' && c != '<' && c != '>' && c != '!')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '|':
+		  if (c != '|')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		case '&':
+		  if (c != '&')
+		    return 0;
+
+		  ++cur;
+		  break;
+
+		default:
+		  break;
+		}
+	      /* Infix operators take two arguments, one on either
+		 side.  Skipping the whitespaces that may happen on the
+		 right side.  */
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	    }
+	  break;
+
+	case '%':
+	    {
+	      ++cur;
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	      if (*cur >= 'a' && *cur <= 'z')
+		{
+		  /* We're dealing with a register name.  */
+		  while (isalnum (*cur))
+		    ++cur;
+
+		  stap_skip_whitespace_cond (&cur, paren_open);
+
+		  /* Some registers (e.g. floating-point register stack
+		     registers on Intel i386) have the following syntax:
+
+		     `%st(0)', `%st(1)', and so on.
+
+		     So it's ok to expect parenthesis here.  */
+		  if (*cur == '(')
+		    {
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		      if (!isdigit (*cur))
+			/* This is an error, since we only expect numbers
+			   inside this parenthesis.  */
+			return 0;
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		      if (*cur != ')')
+			/* We only expect one number.  */
+			return 0;
+		      ++cur;
+		      stap_skip_whitespace_cond (&cur, paren_open);
+		    }
+		}
+	    }
+	  break;
+
+	case '$':
+	    {
+	      /* This is an integer constant.  */
+	      ++cur;
+	      stap_skip_whitespace_cond (&cur, paren_open);
+
+	      while (isdigit (*cur))
+		++cur;
+
+	      stap_skip_whitespace_cond (&cur, paren_open);
+	    }
+	  break;
+
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+	    {
+	      char *old = cur;
+
+	      /* Number.  */
+	      while (isdigit (*cur))
+		++cur;
+
+	      /* We have to do a lookahead here, because the user may
+		 input `2 + 2' (with spaces), and this is not an error.  */
+	      cur = skip_spaces (cur);
+
+	      switch (*cur)
+		{
+		case '+': case '-':
+		  /* We may find the `@' sign, and it means that the
+		     argument has finished, so we shouldn't advance the
+		     pointer.  */
+		  if (cur[1] && (cur[1] == '4' || cur[1] == '8')
+		      && cur[2] && cur[2] == '@')
+		    {
+		      cur = old;
+		      goto fin;
+		    }
+		  break;
+
+		case '*': case '/': case '>': case '<':
+		case '|': case '&': case '^': case '!':
+		  /* This is a binary operation, which means we'll
+		     have to find another number after the operator.  */
+		  break;
+
+		case '(':
+		  /* We may also have sentences in the form:
+
+		     `4 (%rax)'  */
+		  break;
+		}
+	    }
+fin:
+	  break;
+	}
+    }
+
+  *p = cur;
+
+  return 1;
+}
+
+/* Helper function which is responsible for freeing the space allocated to
+   hold information about a probe's arguments.  */
+
+static void
+stap_free_args_info (void *args_info_ptr)
+{
+  struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
+  int i;
+
+  for (i = 0; i < a->n_args; i++)
+    {
+      xfree (a->arg[i].arg_str);
+    }
+
+  xfree (a->arg);
+  xfree (a);
+}
+
+/* Function which parses an argument string from PROBE, correctly splitting
+   the arguments and storing their information in properly ways.  This function
+   only separates the arguments, but does not evaluate them.
+
+   Consider the following argument string:
+
+   `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 stap_args_info *args_info;
+  struct cleanup *back_to;
+  const char *cur = probe->args;
+  int current_arg = -1;
+  /* This is a state-machine parser, which means we will always be
+     in a known state when parsing an argument.  The state could be
+     either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
+     we are parsing the bitness-definition part (i.e., `4@'), or
+     `PARSE_ARG' if we are actually parsing the argument part.  */
+  enum
+    {
+      NEW_ARG,
+      BITNESS,
+      PARSE_ARG,
+    } current_state;
+
+  /* For now, we assume everything is not going to work.  */
+  probe->parsed_args = &dummy_stap_args_info;
+
+  if (!cur || !*cur || *cur == ':')
+    return;
+
+  args_info = xmalloc (sizeof (struct stap_args_info));
+  back_to = make_cleanup (stap_free_args_info, args_info);
+  args_info->arg = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
+
+  /* Ok, let's start.  */
+  current_state = NEW_ARG;
+
+  while (*cur)
+    {
+      switch (current_state)
+	{
+	case NEW_ARG:
+	  ++current_arg;
+
+	  if (current_arg >= STAP_MAX_ARGS)
+	    {
+	      complaint (&symfile_complaints,
+			 _("probe `%s' has more arguments than the maximum "
+			   "allowed"), probe->name);
+	      do_cleanups (back_to);
+	      return;
+	    }
+
+	  current_state = BITNESS;
+	  break;
+
+	case BITNESS:
+	    {
+	      enum stap_arg_bitness b;
+	      int got_minus = 0;
+
+	      /* 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] != '@')
+		{
+		  current_state = PARSE_ARG;
+		  args_info->arg[current_arg].bitness
+		    = STAP_ARG_BITNESS_UNDEFINED;
+		  break;
+		}
+
+	      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->name);
+		  do_cleanups (back_to);
+		  return;
+		}
+
+	      args_info->arg[current_arg].bitness = b;
+	      /* Discard the number and the `@' sign.  */
+	      cur += 2;
+	      /* Move on.  */
+	      current_state = PARSE_ARG;
+	    }
+	  break;
+
+	case PARSE_ARG:
+	    {
+	      const char *start = cur;
+
+	      if (!stap_parse_arg (&cur))
+		{
+		  /* We have tried to parse this argument, but it's
+		     malformed.  This is an error.  */
+		  do_cleanups (back_to);
+		  return;
+		}
+
+	      args_info->arg[current_arg].arg_str
+		= savestring (start, cur - start);
+	      /* Start it over again.  */
+	      cur = skip_spaces ((char *) cur);
+	      current_state = NEW_ARG;
+	    }
+	  break;
+	}
+
+      if (!*cur && current_state != NEW_ARG)
+	{
+	  /* We reached the end of the argument string, but we're
+	     still in the middle of the process of parsing an argument.
+	     It means the argument string is malformed.  */
+	  complaint (&symfile_complaints,
+		     _("malformed argument for probe `%s'"),
+		     probe->name);
+	  do_cleanups (back_to);
+	  return;
+	}
+    }
+
+  args_info->n_args = current_arg + 1;
+  args_info->arg = xrealloc (args_info->arg,
+			      args_info->n_args
+			      * sizeof (struct stap_probe_arg));
+  args_info->probe = probe;
+
+  probe->parsed_args = args_info;
+
+  discard_cleanups (back_to);
+}
+
+/* See definition in stap-probe.h.  */
+
+int
+stap_get_probe_argument_count (const struct stap_probe *probe)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  return probe->parsed_args->n_args;
+}
+
+/* Returns the operator precedence level of OP, or zero if the operator
+   code was not recognized.
+   The levels were taken from the gas manual.  */
+
+static int
+stap_get_operator_prec (enum exp_opcode op)
+{
+  switch (op)
+    {
+    case BINOP_LOGICAL_OR:
+      return 1;
+
+    case BINOP_LOGICAL_AND:
+      return 2;
+
+    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 3;
+
+    case BINOP_BITWISE_IOR: case BINOP_BITWISE_AND:
+    case BINOP_BITWISE_XOR: case UNOP_LOGICAL_NOT:
+      return 4;
+
+    case BINOP_MUL: case BINOP_DIV: case BINOP_REM:
+    case BINOP_LSH: case BINOP_RSH:
+      return 5;
+
+    default:
+      return 0;
+    }
+}
+
+/* Given S, this function reads the operator in it and fills the OP
+   pointer with its code.  Returns 1 on success, zero if the operator
+   was not recognized.  */
+
+static int
+stap_get_opcode (char **s, enum exp_opcode *op)
+{
+  char c = **s;
+  int ret = 1;
+
+  *s += 1;
+
+  switch (c)
+    {
+    case '*':
+      *op = BINOP_MUL;
+      break;
+
+    case '/':
+      *op = BINOP_DIV;
+      break;
+
+    case '%':
+      {
+	if (isalpha (**s))
+	  {
+	    /* Dealing with a register name.  */
+	    ret = 0;
+	    break;
+	  }
+
+	*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 operator OPCODE, this function generates agent bytecode
+   for it.  */
+
+static void
+stap_opcode_to_ax (struct stap_evaluation_info *eval_info,
+		   enum exp_opcode opcode)
+{
+  struct agent_expr *expr = eval_info->aexpr;
+
+  switch (opcode)
+    {
+    case BINOP_MUL:
+      ax_simple (expr, aop_mul);
+      break;
+
+    case BINOP_DIV:
+      ax_simple (expr, aop_div_signed);
+      break;
+
+    case BINOP_REM:
+      ax_simple (expr, aop_rem_unsigned);
+      break;
+
+    case BINOP_LESS:
+      ax_simple (expr, aop_less_signed);
+      break;
+
+    case BINOP_LEQ:
+      /* A <= B is !(B < A) */
+      ax_simple (expr, aop_swap);
+      ax_simple (expr, aop_less_signed);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_GTR:
+      /* A > B is B < A */
+      ax_simple (expr, aop_swap);
+      ax_simple (expr, aop_less_signed);
+      break;
+
+    case BINOP_GEQ:
+      /* A >= B is !(A < B) */
+      ax_simple (expr, aop_less_signed);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_NOTEQUAL:
+      ax_simple (expr, aop_equal);
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_LSH:
+      ax_simple (expr, aop_lsh);
+      break;
+
+    case BINOP_RSH:
+      ax_simple (expr, aop_rsh_unsigned);
+      break;
+
+    case BINOP_BITWISE_IOR:
+      ax_simple (expr, aop_bit_or);
+      break;
+     
+    case BINOP_LOGICAL_OR:
+      error (_("Operator logical-or (`||') not supported yet."));
+      break;
+
+    case BINOP_BITWISE_AND:
+      ax_simple (expr, aop_bit_and);
+      break;
+
+    case BINOP_LOGICAL_AND:
+      error (_("Operator logical-and (`&&') not supported yet."));
+      break;
+
+    case BINOP_BITWISE_XOR:
+      ax_simple (expr, aop_bit_xor);
+      break;
+
+    case UNOP_LOGICAL_NOT:
+      ax_simple (expr, aop_log_not);
+      break;
+
+    case BINOP_ADD:
+      ax_simple (expr, aop_add);
+      break;
+
+    case BINOP_SUB:
+      ax_simple (expr, aop_sub);
+      break;
+
+    case BINOP_EQUAL:
+      ax_simple (expr, aop_equal);
+      break;
+
+    default:
+      error (_("Invalid operator."));
+    }
+}
+
+/* Returns 1 if *S is an operator, zero otherwise.  */
+
+static int
+stap_is_operator (char *s)
+{
+  char op;
+
+  if (!s || !*s)
+    return 0;
+
+  op = *s;
+
+  if (*s == '%' && isalpha (s[1]))
+    /* Register name.  */
+    return 0;
+
+  return (op == '+' || op == '-' || op == '*' || op == '/'
+	  || op == '>' || op == '<' || op == '!' || op == '^'
+	  || op == '|' || op == '&' || op == '%' || op == '=');
+}
+
+/* This function fetches the value of the register whose
+   name starts in the expression buffer.  It also applies any register
+   displacements (e.g., `-4(%eax)'), and indirects the contents of the
+   register (e.g., `(%eax)').  It returns RET if the operation has succeeded,
+   or calls `error' otherwise.  */
+
+static struct value *
+stap_fetch_reg_value (struct stap_evaluation_info *eval_info,
+		      struct value *displacement)
+{
+  const char *start;
+  char *s = eval_info->exp_buf;
+  struct gdbarch *gdbarch = eval_info->gdbarch;
+  struct frame_info *frame = eval_info->frame;
+  enum stap_arg_bitness bitness = eval_info->bitness;
+  char *regname;
+  int len, regnum, indirect_p = 0;
+  struct value *ret = NULL;
+  
+  /* The function which called us did not check if the expression
+     buffer was empty.  */
+  gdb_assert (s && *s);
+
+  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+    /* If we are compiling, we cannot return NULL because that would
+       lead to errors in future evaluations.  That's why we just make
+       this dummy value, representing that the return value of this
+       function is not NULL.  */
+    ret = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
+
+  /* Valid register name on x86 platforms are:
+
+     [paren]%{a-z0-9}[paren]
+
+     Let's check for that here.  */
+  if (*s == '(')
+    {
+      ++s;
+      if (!*s || *s != '%'
+	  || (*s == '%' && !isalpha (s[1])))
+	error (_("Invalid register name on expression `%s'."),
+	       eval_info->saved_expr);
+      ++s;
+      /* The presence of parenthesis means that we want to indirect
+	 the register.  */
+      indirect_p = 1;
+    }
+  else if (*s == '%')
+    {
+      ++s;
+      if (!*s || !isalpha (*s))
+	error (_("Invalid register name on expression `%s'."),
+	       eval_info->saved_expr);
+    }
+  else
+    error (_("Invalid register name on expression `%s'."),
+	   eval_info->saved_expr);
+
+  if (displacement && !indirect_p)
+    /* We cannot apply displacement to non-indirect register access.  */
+    error (_("Trying to apply displacement without indirecting register "
+	     "on expression `%s'."), eval_info->saved_expr);
+
+  /* Ok, let's calculate the size of the register name.  */
+  start = s;
+  while (isalnum (*s))
+    ++s;
+
+  len = s - start;
+
+  if (indirect_p && *s == ')')
+    ++s;
+
+  regname = alloca (len + 1);
+  strncpy (regname, start, len);
+  regname[len] = '\0';
+
+  /* Translating the register name into the corresponding number.  */
+  regnum = user_reg_map_name_to_regnum (gdbarch, regname, len);
+
+  if (regnum == -1)
+    error (_("Invalid register name `%s' on expression `%s'."),
+	   regname, eval_info->saved_expr);
+
+  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+    ax_reg (eval_info->aexpr, regnum);
+  else
+    ret = value_of_register (regnum, frame);
+
+  if (indirect_p)
+    {
+      struct type *t = NULL;
+      enum agent_op aop = aop_ref32;
+
+      /* If the user has specified that the register must be indirected,
+	 we should know what's the correct type to cast it before making
+	 the indirection.  This type corresponds to the bitness specified
+	 before the `@' sign on the argument string, or it defaults to
+	 `unsigned long' if the `@' were not present.  */
+
+      switch (bitness)
+	{
+	case STAP_ARG_BITNESS_UNDEFINED:
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    {
+	      if (gdbarch_addr_bit (gdbarch) == 32)
+		aop = aop_ref32;
+	      else
+		aop = aop_ref64;
+	    }
+	  else
+	    {
+	      if (gdbarch_addr_bit (gdbarch) == 32)
+		t = lookup_pointer_type
+		  (builtin_type (gdbarch)->builtin_uint32);
+	      else
+		t = lookup_pointer_type
+		  (builtin_type (gdbarch)->builtin_uint64);
+	    }
+	  break;
+
+	case STAP_ARG_BITNESS_32BIT_SIGNED:
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    aop = aop_ref32;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_int32);
+	  break;
+
+	case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    aop = aop_ref32;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_uint32);
+	  break;
+
+	case STAP_ARG_BITNESS_64BIT_SIGNED:
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    aop = aop_ref64;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_int64);
+	  break;
+
+	case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    aop = aop_ref64;
+	  else
+	    t = lookup_pointer_type
+	      (builtin_type (gdbarch)->builtin_uint64);
+	  break;
+
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("Undefined bitness for probe."));
+	  break;
+	}
+
+      if (displacement)
+	{
+	  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	    {
+	      ax_const_l (eval_info->aexpr, value_as_long (displacement));
+	      ax_simple (eval_info->aexpr, aop_add);
+	    }
+	  else
+	    ret = value_ptradd (ret, value_as_long (displacement));
+	}
+
+      if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	{
+	  if (trace_kludge)
+	    {
+	      gdb_assert (aop == aop_ref32 || aop == aop_ref64);
+	      ax_trace_quick (eval_info->aexpr, aop == aop_ref32 ? 4 : 8);
+	    }
+	  ax_simple (eval_info->aexpr, aop);
+	}
+      else
+	{
+	  ret = value_cast (t, ret);
+	  ret = value_ind (ret);
+	}
+    }
+
+  /* Updating the expression buffer pointer, because we have made
+     some modifications to it before.  */
+  eval_info->exp_buf = s;
+
+  return ret;
+}
+
+/* This function tries to evaluate a single operand of the expression.
+
+   Single operands can be:
+
+   - unary operators `-' and `~';
+   - integer constants (beginning with `$');
+   - register access, with/out displacement and indirection.  */
+
+static struct value *
+stap_evaluate_single_operand (struct stap_evaluation_info *eval_info)
+{
+  struct gdbarch *gdbarch = eval_info->gdbarch;
+  struct frame_info *frame = eval_info->frame;
+  enum stap_arg_bitness bitness = eval_info->bitness;
+  struct value *res = NULL;
+
+  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+    /* If we are compiling, we cannot return NULL because that would
+       lead to errors in future evaluations.  That's why we just make
+       this dummy value, representing that the return value of this
+       function is not NULL.  */
+    res = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
+
+  switch (*eval_info->exp_buf)
+    {
+    case '-': case '~':
+	{
+	  char c = *eval_info->exp_buf;
+
+	  /* This is an unary operator (either `-' or `~').
+
+	     If it is followed by a parenthesis, and this parenthesis
+	     is NOT followed by a `%', then we are dealing with an expression
+	     like `-(2 + 3)' or `~(2 + 3)'.  We just have to treat separately
+	     and return the result after applying the operation (`-' or `~').
+
+	     If it is followed by a digit, then we have only one choice:  it
+	     is a displacement argument for a register access, like
+	     `-4(%eax)'.  It also means that the operator can *only* be `-',
+	     and the characters immediately after the number *must* be `(%'.
+
+	     If it is followed by a `$', then it is an integer constant, and
+	     we should apply the correct operation to it.  */
+
+	  ++eval_info->exp_buf;
+	  eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+	  if (*eval_info->exp_buf
+	      && *eval_info->exp_buf == '('
+	      && eval_info->exp_buf[1] != '%')
+	    {
+	      struct value *tmp_res;
+
+	      /* We're not dealing with a register name, but with an
+		 expression like `-(2 + 3)' or `~(2 + 3)'.  We first have
+		 to evaluate the right side of the expression (i.e., the
+		 parenthesis), and then apply the specified operation
+		 (either `-' or `~') to it.  */
+	      tmp_res = stap_evaluate_conditionally (eval_info);
+
+	      if (c == '-')
+		{
+		  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+		    {
+		      /* We have to add `-1' to the stack, and multiply
+			 the two values.  */
+		      ax_const_l (eval_info->aexpr, -1);
+		      ax_simple (eval_info->aexpr, aop_mul);
+		    }
+		  else
+		    res = value_neg (tmp_res);
+		}
+	      else
+		{
+		  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+		    ax_simple (eval_info->aexpr, aop_bit_not);
+		  else
+		    res = value_complement (tmp_res);
+		}
+	    }
+	  else if (isdigit (*eval_info->exp_buf))
+	    {
+	      int number;
+
+	      /* This is a number, so it MUST be a register displacement.
+		 The only operator allowed here is `-', it MUST be
+		 followed by a number, and the number MUST be followed by
+		 `(%'.  */
+	      if (c != '-')
+		error (_("Invalid operator `%c' for register displacement "
+			 "on expression `%s'."), c, eval_info->saved_expr);
+
+	      number = strtol (eval_info->exp_buf,
+			       &eval_info->exp_buf, 0) * -1;
+
+	      if (!*eval_info->exp_buf
+		  || *eval_info->exp_buf != '('
+		  || (*eval_info->exp_buf == '('
+		      && eval_info->exp_buf[1] != '%'))
+		error (_("Invalid method of indirecting a register on "
+			 "expression `%s'."), eval_info->saved_expr);
+
+	      res
+		= value_from_longest (builtin_type (gdbarch)->builtin_int,
+				      number);
+
+	      res = stap_fetch_reg_value (eval_info, res);
+	    }
+	  else if (*eval_info->exp_buf == '$')
+	    {
+	      int number;
+
+	      /* Last case.  We are dealing with an integer constant, so
+		 we must read it and then apply the necessary operation,
+		 either `-' or `~'.  */
+	      ++eval_info->exp_buf;
+	      number = strtol (eval_info->exp_buf,
+			       &eval_info->exp_buf, 0);
+
+	      if (!STAP_COMPILING_AGENT_EXPR_P (eval_info))
+		res
+		  = value_from_longest (builtin_type (gdbarch)->builtin_int,
+					number);
+	      else
+		ax_const_l (eval_info->aexpr, number);
+
+	      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+	      if (c == '-')
+		{
+		  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+		    ax_simple (eval_info->aexpr, aop_log_not);
+		  else
+		    res = value_neg (res);
+		}
+	      else
+		{
+		  if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+		    ax_simple (eval_info->aexpr, aop_bit_not);
+		  else
+		    res = value_complement (res);
+		}
+	    }
+	  else
+	    error (_("Invalid operand to unary operator `%c' on "
+		     "expression `%s'."), c, eval_info->saved_expr);
+	}
+      break;
+
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      {
+	int number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+	/* This is a register displacement with a positive value.  We read
+	   the number, and then check for the mandatory `(%' part.  */
+	if (!*eval_info->exp_buf
+	    || !(*eval_info->exp_buf == '('
+		 && eval_info->exp_buf[1] == '%'))
+	  error (_("Invalid register access on expression `%s'."),
+		 eval_info->saved_expr);
+
+	res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				  number);
+
+	res = stap_fetch_reg_value (eval_info, res);
+      }
+    break;
+
+    case '$':
+      {
+	int number;
+
+	/* This is an integer constant.  We just have to read the number
+	   and return it.  */
+	++eval_info->exp_buf;
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+	number = strtol (eval_info->exp_buf, &eval_info->exp_buf, 0);
+
+	if (STAP_COMPILING_AGENT_EXPR_P (eval_info))
+	  ax_const_l (eval_info->aexpr, number);
+	else
+	  res = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				    number);
+
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+      }
+    break;
+
+    case '(': case '%':
+      {
+	/* Register access, with or without indirection.  */
+	res = stap_fetch_reg_value (eval_info, /*displacement=*/NULL);
+	eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+      }
+    break;
+
+    default:
+      {
+	error (_("Operator `%c' not recognized on expression `%s'."),
+	       *eval_info->exp_buf, eval_info->saved_expr);
+      }
+    }
+
+  return res;
+}
+
+/* This function is responsible for checking the necessary type of evaluation
+   depending on what is the next "thing" in the buffer.  Valid values are:
+
+   - Unary operators;
+   - Integer constants;
+   - Register displacement, indirection, and direct access;
+   - Parenthesized operand.  */
+
+static struct value *
+stap_evaluate_conditionally (struct stap_evaluation_info *eval_info)
+{
+  char *s = eval_info->exp_buf;
+  struct value *ret = NULL;
+
+  if (*s == '-' || *s == '~' /* Unary operators.  */
+      || *s == '$' /* Number (integer constant).  */
+      || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement.  */
+      || (*s == '(' && s[1] == '%') /* Register indirection.  */
+      || (*s == '%' && isalpha (s[1]))) /* Register value.  */
+    /* This is a single operand, so just evaluate it and return.  */
+    ret = stap_evaluate_single_operand (eval_info);
+  else if (*s == '(')
+    {
+      /* We are dealing with a parenthesized operand.  It means we
+	 have to evaluate it as it was a separate expression, without
+	 left-side or precedence.  */
+      ++eval_info->exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+      ret = stap_evaluate_probe_argument_2 (eval_info,
+					    /*lhs=*/NULL, /*prec=*/0);
+
+      if (*eval_info->exp_buf != ')')
+	error (_("Missign close-paren on expression `%s'."),
+	       eval_info->saved_expr);
+
+      ++eval_info->exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+    }
+  else
+    error (_("Cannot evaluate expression `%s'."),
+	   eval_info->saved_expr);
+
+  return ret;
+}
+
+/* Evaluation function for probe's argument expressions.  LHS represents
+   the left side of the expression, and PREC is the precedence of the
+   last operator identified before calling the function.  */
+
+static struct value *
+stap_evaluate_probe_argument_2 (struct stap_evaluation_info *eval_info,
+				struct value *lhs, int prec)
+{
+  struct value *rhs = NULL;
+  int compiling_p = STAP_COMPILING_AGENT_EXPR_P (eval_info);
+
+  /* This is an operator-precedence parser and evaluator.
+
+     We work with left- and right-sides of expressions, and
+     evaluate them depending on the precedence of the operators
+     we find.  */
+
+  eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+  if (!lhs)
+    /* We were called without a left-side, either because this is the
+       first call, or because we were called to evaluate a parenthesized
+       expression.  It doesn't really matter; we have to evaluate the
+       left-side in order to continue the process.  */
+    lhs = stap_evaluate_conditionally (eval_info);
+
+  /* Start to evaluate 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 (eval_info->exp_buf
+	 && *eval_info->exp_buf
+	 && *eval_info->exp_buf != ')')
+    {
+      char *tmp_exp_buf;
+      enum exp_opcode opcode;
+      int cur_prec;
+
+      if (!stap_is_operator (eval_info->exp_buf))
+	error (_("Invalid operator `%c' on expression `%s'."),
+	       *eval_info->exp_buf, eval_info->saved_expr);
+
+      /* 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 = eval_info->exp_buf;
+      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 evaluation process began, it means we should stop evaluating
+	   and return.  */
+	break;
+
+      eval_info->exp_buf = tmp_exp_buf;
+      eval_info->exp_buf = skip_spaces (eval_info->exp_buf);
+
+      /* Evaluate the right-side of the expression.  */
+      rhs = stap_evaluate_conditionally (eval_info);
+
+      /* While we still have operators, try to evaluate another
+	 right-side, but using the current right-side as a left-side.  */
+      while (*eval_info->exp_buf
+	     && stap_is_operator (eval_info->exp_buf))
+	{
+	  enum exp_opcode lookahead_opcode;
+	  int lookahead_prec;
+
+	  /* Saving the current expression buffer position.  The explanation
+	     is the same as above.  */
+	  tmp_exp_buf = eval_info->exp_buf;
+	  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;
+
+	  rhs = stap_evaluate_probe_argument_2 (eval_info,
+						rhs, lookahead_prec);
+	}
+
+      /* Now, "join" both left and right sides into one left-side, using
+	 the specified operator.  */
+      if (compiling_p)
+	stap_opcode_to_ax (eval_info, opcode);
+      else
+	lhs = value_binop (lhs, rhs, opcode);
+    }
+
+  return lhs;
+}
+
+/* This function fills the necessary arguments for the evaluation function
+   to work.  */
+
+static struct value *
+stap_evaluate_probe_argument_1 (struct objfile *objfile,
+				const struct stap_probe *probe,
+				struct frame_info *frame,
+				int n)
+{
+  struct stap_evaluation_info eval_info;
+  char *s = (char *) probe->parsed_args->arg[n].arg_str;
+  struct value *res, *vs[4];
+
+  /* Filling necessary information for evaluation function.  */
+  eval_info.saved_expr = s;
+  eval_info.exp_buf = s;
+  eval_info.gdbarch = get_objfile_arch (objfile);
+  eval_info.frame = frame;
+  eval_info.bitness = probe->parsed_args->arg[n].bitness;
+  /* We are not compiling to an agent expression.  */
+  eval_info.aexpr = NULL;
+  eval_info.avalue = NULL;
+
+  res = stap_evaluate_probe_argument_2 (&eval_info,
+					/*lhs=*/NULL, /*prec=*/0);
+
+  if (!res)
+    error (_("Could not evaluate expression `%s'."),
+	   eval_info.saved_expr);
+
+  return res;
+}
+
+/* See definition in stap-probe.h.  */
+
+struct value *
+stap_evaluate_probe_argument (struct objfile *objfile,
+			      const struct stap_probe *probe,
+			      struct frame_info *frame,
+			      int n)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  if (!probe->parsed_args->arg
+      || n >= probe->parsed_args->n_args)
+    return NULL;
+
+  return stap_evaluate_probe_argument_1 (objfile, probe, frame, n);
+}
+
+/* Helper function which compiles the probe's argument N into an
+   agent expression, suitable for using with tracepoints.  */
+
+static void
+stap_compile_to_ax_1 (struct objfile *objfile,
+		      const struct stap_probe *probe,
+		      struct agent_expr *expr,
+		      struct axs_value *value,
+		      int n)
+{
+  struct stap_evaluation_info eval_info;
+  struct gdbarch *gdbarch = expr->gdbarch;
+  char *s = (char *) probe->parsed_args->arg[n].arg_str;
+
+  /* Filling necessary information for evaluation function.  */
+  eval_info.saved_expr = s;
+  eval_info.exp_buf = s;
+  eval_info.gdbarch = expr->gdbarch;
+  eval_info.frame = NULL;
+  eval_info.bitness = probe->parsed_args->arg[n].bitness;
+  /* We are compiling to an agent expression.  */
+  eval_info.aexpr = expr;
+  eval_info.avalue = value;
+
+  /* We can always use this kind.  */
+  value->kind = axs_rvalue;
+
+  /* Figuring out the correct type for this axs_value.  */
+  switch (eval_info.bitness)
+    {
+    case STAP_ARG_BITNESS_UNDEFINED:
+      if (gdbarch_addr_bit (gdbarch) == 32)
+	value->type = builtin_type (gdbarch)->builtin_uint32;
+      else
+	value->type = builtin_type (gdbarch)->builtin_uint64;
+      break;
+
+    case STAP_ARG_BITNESS_32BIT_SIGNED:
+      value->type = builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+      value->type = builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case STAP_ARG_BITNESS_64BIT_SIGNED:
+      value->type = builtin_type (gdbarch)->builtin_int64;
+      break;
+
+    case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+      value->type = builtin_type (gdbarch)->builtin_uint64;
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Undefined bitness for probe."));
+      break;
+    }
+
+  stap_evaluate_probe_argument_2 (&eval_info,
+				  /*lhs=*/NULL, /*prec=*/0);
+}
+
+/* See definition in stap-probe.h.  */
+
+void
+stap_compile_to_ax (struct objfile *objfile,
+		    const struct stap_probe *probe,
+		    struct agent_expr *expr,
+		    struct axs_value *value,
+		    int n)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments ((struct stap_probe *) probe);
+
+  if (!probe->parsed_args->arg
+      || n >= probe->parsed_args->n_args)
+    return;
+
+  stap_compile_to_ax_1 (objfile, probe, expr, value, n);
+}
+
+struct value *
+stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
+{
+  const struct stap_probe *probe;
+  struct objfile *objfile;
+  int 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,
+								  frame,
+								  n);
+}
+
+/* This function frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+void
+stap_free_parsed_args (struct stap_args_info *parsed_args)
+{
+  int i;
+
+  if (!parsed_args
+      || parsed_args == &dummy_stap_args_info
+      || parsed_args->n_args == 0)
+    return;
+
+  for (i = 0; i < parsed_args->n_args; i++)
+    xfree (parsed_args->arg);
+
+  xfree (parsed_args);
+}
+
+/* A utility structure.  A VEC of these is built when handling "info
+   probes".  */
+
+struct stap_probe_and_objfile
+{
+  /* The probe.  */
+  const struct stap_probe *probe;
+  /* The probe's objfile.  */
+  struct objfile *objfile;
+};
+
+typedef struct stap_probe_and_objfile stap_entry;
+DEF_VEC_O (stap_entry);
+
+/* 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.
+   Each argument is a regexp, or NULL, which matches anything.  */
+
+static VEC (stap_entry) *
+collect_probes (char *objname, char *provider, char *probe)
+{
+  struct objfile *objfile;
+  VEC (stap_entry) *result = NULL;
+  struct cleanup *cleanup;
+  regex_t obj_pat, prov_pat, probe_pat;
+
+  cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
+
+  compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
+  compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
+  compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	stap_entry entry;
+
+	if (provider)
+	  {
+	    if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	if (probe)
+	  {
+	    if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	entry.probe = &probes[i];
+	entry.objfile = objfile;
+	VEC_safe_push (stap_entry, result, &entry);
+      }
+  }
+
+  discard_cleanups (cleanup);
+  return result;
+}
+
+/* A qsort comparison function for stap_entry objects.  */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+  const stap_entry *ea = a;
+  const stap_entry *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);
+}
+
+/* Implementation of the "info probes" command.  */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+  char *provider, *probe = NULL, *objname = NULL;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  VEC (stap_entry) *items;
+  int i, addr_width, any_found;
+  stap_entry *entry;
+
+  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);
+	}
+    }
+
+  items = collect_probes (objname, provider, probe);
+  make_cleanup (VEC_cleanup (stap_entry), &items);
+  make_cleanup_ui_out_table_begin_end (uiout, 5,
+				       VEC_length (stap_entry, items),
+				       "SystemTapProbes");
+
+  if (! VEC_empty (stap_entry, items))
+    qsort (VEC_address (stap_entry, items),
+	   VEC_length (stap_entry, items),
+	   sizeof (stap_entry),
+	   compare_entries);
+
+  addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
+
+  ui_out_table_header (uiout, 10, ui_left, "provider", _("Provider"));
+  ui_out_table_header (uiout, 10, ui_left, "name", _("Name"));
+  ui_out_table_header (uiout, addr_width - 1, ui_left, "addr", _("Where"));
+  ui_out_table_header (uiout, addr_width - 1, ui_left, "semaphore",
+		       _("Semaphore"));
+  ui_out_table_header (uiout, 30, ui_left, "object", _("Object"));
+  ui_out_table_body (uiout);
+
+  for (i = 0; VEC_iterate (stap_entry, items, i, entry); ++i)
+    {
+      struct cleanup *inner;
+
+      inner = make_cleanup_ui_out_tuple_begin_end (uiout, "probe");
+
+      ui_out_field_string (uiout, "provider", entry->probe->provider);
+      ui_out_field_string (uiout, "name", entry->probe->name);
+      ui_out_field_core_addr (uiout, "addr", get_current_arch (),
+			      entry->probe->address);
+      if (entry->probe->sem_addr == 0)
+	ui_out_field_skip (uiout, "semaphore");
+      else
+      ui_out_field_core_addr (uiout, "semaphore", get_current_arch (),
+			      entry->probe->sem_addr);
+      ui_out_field_string (uiout, "object", entry->objfile->name);
+      ui_out_text (uiout, "\n");
+
+      do_cleanups (inner);
+    }
+
+  any_found = ! VEC_empty (stap_entry, items);
+  do_cleanups (cleanup);
+
+  if (! any_found)
+    ui_out_message (uiout, 0, _("No probes matched.\n"));
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+const struct stap_probe *
+find_probe_in_objfile (struct objfile *objfile,
+		       const char *provider,
+		       const char *name)
+{
+  const struct stap_probe *probes;
+  int i, num_probes;
+
+  if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+    return NULL;
+
+  probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+  for (i = 0; i < num_probes; ++i)
+    {
+      if (strcmp (probes[i].provider, provider) != 0)
+	continue;
+
+      if (strcmp (probes[i].name, name) != 0)
+	continue;
+
+      return &probes[i];
+    }
+
+  return NULL;
+}
+
+/* See definition in stap-probe.h.  */
+
+struct symtabs_and_lines
+parse_stap_probe (char **argptr, struct linespec_result *canonical)
+{
+  char *full_arg = extract_arg (argptr);
+  char *arg = xstrdup (full_arg);
+  char *objfile_name = NULL, *provider = NULL, *name, *p;
+  struct cleanup *cleanup;
+  struct symtabs_and_lines result;
+  struct objfile *objfile;
+
+  result.sals = NULL;
+  result.nelts = 0;
+
+  /* The caller ensured that this starts with 'probe:'.  */
+  gdb_assert (arg && strncmp (arg, "probe:", 6) == 0);
+  cleanup = make_cleanup (xfree, arg);
+  make_cleanup (xfree, full_arg);
+  arg += 6;
+
+  /* Extract each word from the argument, separated by ":"s.  */
+  p = strchr (arg, ':');
+  if (p == NULL)
+    {
+      /* This is `probe:name'.  */
+      name = arg;
+    }
+  else
+    {
+      char *hold = p + 1;
+
+      *p = '\0';
+      p = strchr (hold, ':');
+      if (p == NULL)
+	{
+	  /* This is `probe:provider:name'.  */
+	  provider = arg;
+	  name = hold;
+	}
+      else
+	{
+	  /* This is `probe: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"));
+
+  if (canonical)
+    canonical->canonical = NULL;
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+
+    if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+      continue;
+
+    if (objfile_name
+	&& FILENAME_CMP (objfile->name, objfile_name) != 0
+	&& FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+      continue;
+
+    probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	struct symtab_and_line *sal;
+
+	if (provider && strcmp (probes[i].provider, provider) != 0)
+	  continue;
+
+	if (strcmp (probes[i].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 = probes[i].address;
+	sal->explicit_pc = 1;
+	sal->section = find_pc_overlay (sal->pc);
+	sal->pspace = current_program_space;
+	sal->semaphore = probes[i].sem_addr;
+
+	if (canonical)
+	  {
+	    canonical->canonical = xrealloc (canonical->canonical,
+					     result.nelts * sizeof (char **));
+	    canonical->canonical[result.nelts - 1] = xstrdup (full_arg);
+	  }
+      }
+  }
+
+  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;
+    }
+
+  do_cleanups (cleanup);
+
+  return result;
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+const struct stap_probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+  {
+    const struct stap_probe *probes;
+    int i, num_probes;
+    stap_entry entry;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	if (probes[i].address == pc)
+	  {
+	    *objfile_out = objfile;
+	    return &probes[i];
+	  }
+      }
+  }
+
+  return NULL;
+}
+
+/* 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;
+  const struct stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL==10 means "_probe_argc".  */
+  gdb_assert (sel >= 0 && sel <= STAP_MAX_ARGS);
+
+  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 == 10)
+    return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
+
+  if (sel >= n_probes)
+    error (_("Invalid probe argument %d -- probe has %d arguments available"),
+	   sel, n_probes);
+
+  return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+								  pc_probe,
+								  frame, 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;
+  const struct stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL==10 means "_probe_argc".  */
+  gdb_assert (sel >= 0 && sel <= 10);
+
+  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 == 10)
+    {
+      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
+
+/* Implementation of `$_probe_arg*' set of variables.  */
+
+static const struct internalvar_funcs probe_funcs =
+{
+  compute_probe_arg,
+  compile_probe_arg,
+  NULL
+};
+
+void
+_initialize_stap_probe (void)
+{
+  add_info ("probes", info_probes_command, _("\
+Show available static probes.\n\
+Usage: info probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT match the executable or shared library name."));
+
+  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
+				(void *) (uintptr_t) 10);
+  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);
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..391d96f
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,109 @@
+/* SystemTap probe support for GDB.
+
+   Copyright (C) 2011 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
+
+struct stap_args_info;
+struct axs_value;
+struct linespec_result;
+
+/* Main structure which holds information about a SystemTap probe.  */
+
+struct stap_probe
+{
+  /* The provider of this probe.  */
+  const char *provider;
+
+  /* The name of the probe.  */
+  const char *name;
+
+  /* The address where the probe is inserted.  */
+  CORE_ADDR address;
+
+  /* The address of the probe's semaphore, or 0 if this probe does not
+     have an associated semaphore.  */
+  CORE_ADDR sem_addr;
+
+  /* Probe's arguments.  Users should generally not examine this, but
+     should instead extract information about the arguments using the
+     methods provided in sym_probe_fns.  */
+  const char *args;
+
+  /* Probe's arguments after parsing.  This is an opaque structure that
+     will hold information about the arguments pointed by ARGS.  */
+  struct stap_args_info *parsed_args;
+};
+
+
+/* A helper for linespec that decodes a stap probe specification.  It
+   returns a symtabs_and_lines object and updates *ARGPTR or throws an
+   error.  */
+
+extern struct symtabs_and_lines parse_stap_probe (char **argptr,
+						  struct linespec_result *canon);
+
+/* Search OBJFILE for a probe with the given PROVIDER and NAME.  If a
+   probe is found, return it.  If no probe is found, return NULL.  */
+
+extern const struct stap_probe *find_probe_in_objfile (struct objfile *objfile,
+						       const char *provider,
+						       const char *name);
+
+/* Given a PC, find an associated SystemTap probe.  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 const struct stap_probe *find_probe_by_pc (CORE_ADDR pc,
+						  struct objfile **objfile_out);
+
+/* Given PROBE, returns the number of arguments present in that probe's
+   argument string.  */
+
+extern int stap_get_probe_argument_count (const struct stap_probe *probe);
+
+/* Given PARSED_ARGS, frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+extern void stap_free_parsed_args (struct stap_args_info *parsed_args);
+
+/* Evaluates the probe's argument N, returning a value corresponding
+   to it.  */
+
+extern struct value *stap_evaluate_probe_argument (struct objfile *objfile,
+						   const struct stap_probe *probe,
+						   struct frame_info *frame,
+						   int n);
+
+/* Compile the probe's argument N to agent expression.  */
+
+extern void stap_compile_to_ax (struct objfile *objfile,
+				const struct stap_probe *probe,
+				struct agent_expr *expr,
+				struct axs_value *value,
+				int n);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+   evaluates argument N.  If there is no probe at that location, or if
+   the probe does not have enough arguments, this returns NULL.  */
+
+extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
+					       int n);
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 8925482..d9cff2c 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -31,6 +31,11 @@ struct objfile;
 struct obj_section;
 struct obstack;
 struct block;
+struct stap_probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
 
 /* Comparison function for symbol look ups.  */
 
@@ -297,6 +302,52 @@ struct quick_symbol_functions
 				void *data);
 };
 
+/* Structure of functions used for SystemTap probe support.  If one of
+   these functions is provided, all must be.  */
+
+struct sym_probe_fns
+{
+  /* If non-NULL, return an array of SystemTap probe objects.  The
+     number of objects is returned in *NUM_PROBES.  */
+  const struct stap_probe *(*sym_get_probes) (struct objfile *,
+					      int *num_probes);
+
+  /* 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.  */
+  int (*sym_get_probe_argument_count) (struct objfile *objfile,
+				       const struct stap_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,
+						const struct stap_probe *probe,
+						struct frame_info *frame,
+						int 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,
+			     const struct stap_probe *probe,
+			     struct agent_expr *expr,
+			     struct axs_value *value,
+			     int 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 +418,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 cfceef6..a540cd6 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -765,6 +765,7 @@ init_sal (struct symtab_and_line *sal)
   sal->end = 0;
   sal->explicit_pc = 0;
   sal->explicit_line = 0;
+  sal->semaphore = 0;
 }
 \f
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 4913e6c..a913fa4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1099,6 +1099,10 @@ struct symtab_and_line
   CORE_ADDR end;
   int explicit_pc;
   int explicit_line;
+
+  /* If non-zero, the semaphore location associated with a SystemTap
+     probe.  */
+  CORE_ADDR semaphore;
 };
 
 extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9ae251b..585fa2c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2011-04-08  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.cp/nextoverthrow.exp: Add check for SystemTap probe in
+	libgcc's unwinder.
+	* gdb.trace/stap-trace.c: New file.
+	* gdb.trace/stap-trace.exp: New file.
+
 2011-04-04  Tom Tromey  <tromey@redhat.com>
 
 	* gdb.cp/maint.exp (test_help): Update.
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index d58c519..abb1b05 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -607,6 +607,17 @@ 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>} \
     }
 
 #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..47e4b39
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,69 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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 teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_two_semaphore
+
+#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
+
+void
+m1 (void)
+{
+  if (TEST2)
+    STAP_PROBE (teste, two);
+}
+
+void
+m2 (void)
+{
+  if (TEST2)
+    STAP_PROBE (teste, two);
+}
+
+int
+f (int x)
+{
+  if (TEST)
+    STAP_PROBE1(teste, user, x);
+  return x+5;
+}
+
+int
+main()
+{
+  f(f(23));
+  m1();
+  m2();
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..3fb7377
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,72 @@
+# Copyright (C) 2011 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 {$arg != ""} {
+    	set arg "additional_flags=$arg"
+	set addendum ", with semaphore"
+    } else {
+	set addendum ", no semaphore"
+    }
+
+    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$addendum"
+
+    gdb_test "info probes" \
+	"teste *user *$hex .*" \
+	"info probes$addendum"
+    
+    if {[runto "probe:teste:user"]} {
+	pass "run to probe:teste:user$addendum"
+    } else {
+	fail "run to probe:teste:user$addendum"
+    }
+
+    # Test probe arguments.
+    gdb_test "print \$_probe_argc" " = 1" "print \$_probe_argc$addendum"
+    gdb_test "print \$_probe_arg0 == x" " = 1" "check \$_probe_arg0$addendum"
+    gdb_test "print \$_probe_arg1" \
+    	"Invalid probe argument 1 -- probe has 1 arguments available" \
+    	"check \$_probe_arg1$addendum"
+
+    # Set a breakpoint with multiple probe locations.
+    gdb_test "break probe:teste:two" \
+	"Breakpoint .* at $hex.*2 locations.*" \
+	"set multi-location probe breakpoint$addendum"
+
+    return 0
+}
+
+if {[stap_test] == -1} {
+    untested stap-probe.exp
+    return -1
+}
+stap_test "-DUSE_PROBES"
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 89c02d6..a970bb9 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -53,6 +53,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..27f317e
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.c
@@ -0,0 +1,71 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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 teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_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 (teste, two, x);
+}
+
+int
+f (int x)
+{
+  if (TEST)
+    STAP_PROBE1(teste, 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..189355f
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.exp
@@ -0,0 +1,129 @@
+# Copyright 2011
+# 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"
+
+if $tracelevel then {
+	strace $tracelevel
+}
+
+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:user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "probe:two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 8d33fa7..f96f59d 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -1600,6 +1600,8 @@ start_tracing (void)
 
   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))
@@ -1608,6 +1610,9 @@ start_tracing (void)
       t->number_on_target = 0;
       target_download_tracepoint (t);
       t->number_on_target = t->number;
+
+      for (loc = t->loc; loc; loc = loc->next)
+	modify_semaphore (loc, 1);
     }
   VEC_free (breakpoint_p, tp_vec);
 
@@ -1669,7 +1674,28 @@ trace_stop_command (char *args, int from_tty)
 void
 stop_tracing (void)
 {
+  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)
+	modify_semaphore (loc, 0);
+    }
+
+  VEC_free (breakpoint_p, tp_vec);
+
   /* Should change in response to reply?  */
   current_trace_status ()->running = 0;
 }
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index fd60447..4ef8424 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3090,6 +3090,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
 };
 

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-07 17:04   ` Tom Tromey
@ 2011-04-11  3:21     ` Yao Qi
  0 siblings, 0 replies; 83+ messages in thread
From: Yao Qi @ 2011-04-11  3:21 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Sergio Durigan Junior, gdb-patches

On 04/08/2011 01:04 AM, Tom Tromey wrote:
>>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
> 
>>> +  pc_probe = find_probe_by_pc (pc, &objfile);
> 
> Yao> I don't understand this part.  We are looking for probe by matching
> Yao> frame's PC here, but address of stap_probe is the address where the
> Yao> probe is inserted.  So, probably, we can't find any probe here, is that
> Yao> correct?
> 
> I believe that the frame PC here actually is the location of the probe.
> Is there a situation where this would not be the case?
> 

No.  I misunderstood it.  Thanks for your explanation.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-08 12:38   ` Sergio Durigan Junior
@ 2011-04-11  3:52     ` Yao Qi
  2011-08-12 15:45     ` Jan Kratochvil
  1 sibling, 0 replies; 83+ messages in thread
From: Yao Qi @ 2011-04-11  3:52 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey

On 04/08/2011 08:37 PM, Sergio Durigan Junior wrote:
> +static void
> +stap_compile_to_ax_1 (struct objfile *objfile,
> +		      const struct stap_probe *probe,
> +		      struct agent_expr *expr,
> +		      struct axs_value *value,
> +		      int n)
> +{
> +  struct stap_evaluation_info eval_info;
> +  struct gdbarch *gdbarch = expr->gdbarch;
> +  char *s = (char *) probe->parsed_args->arg[n].arg_str;
> +
> +  /* Filling necessary information for evaluation function.  */
> +  eval_info.saved_expr = s;
> +  eval_info.exp_buf = s;
> +  eval_info.gdbarch = expr->gdbarch;
> +  eval_info.frame = NULL;
> +  eval_info.bitness = probe->parsed_args->arg[n].bitness;
> +  /* We are compiling to an agent expression.  */
> +  eval_info.aexpr = expr;
> +  eval_info.avalue = value;
> +
> +  /* We can always use this kind.  */
> +  value->kind = axs_rvalue;
> +
> +  /* Figuring out the correct type for this axs_value.  */
> +  switch (eval_info.bitness)
> +    {
> +    case STAP_ARG_BITNESS_UNDEFINED:
> +      if (gdbarch_addr_bit (gdbarch) == 32)
> +	value->type = builtin_type (gdbarch)->builtin_uint32;
> +      else
> +	value->type = builtin_type (gdbarch)->builtin_uint64;
> +      break;

Do we have to consider the case when gdbarch_addr_bit returns 16?

> +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;
> +  const struct stap_probe *pc_probe;
> +  int n_probes;
> +
> +  /* SEL==10 means "_probe_argc".  */
> +  gdb_assert (sel >= 0 && sel <= 10);

`10' can be replaced by STAP_MAX_ARGS, as you fixed in compute_probe_arg.

> +
> +  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 == 10)
> +    {
> +      value->kind = axs_rvalue;
> +      value->type = builtin_type (expr->gdbarch)->builtin_int;
> +      ax_const_l (expr, n_probes);
> +      return;
> +    }
> +
> +  gdb_assert (sel >= 0);

It is a redundant check.

The whole patch looks pretty nice to me, and I have no other comments.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-04  3:09 [PATCH 4/6] Implement support for SystemTap probes Sergio Durigan Junior
                   ` (2 preceding siblings ...)
  2011-04-07  2:41 ` Yao Qi
@ 2011-04-19 16:42 ` Jan Kratochvil
  2012-05-07 19:36   ` Jan Kratochvil
  3 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-04-19 16:42 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey

Hi Sergio,

there is still the bug as present on Fedora 15 with:
	glibc-2.13.90-9.x86_64
	glibc-debuginfo-2.13.90-9.x86_64

(gdb) info probes 
Provider   Name       Where               Semaphore           Object                         
libc       lll_futex_wake 0x00007ffff61a5f7b                      /lib64/libc.so.6               
libc       lll_futex_wake 0x00007ffff61a5f7b                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
libc       lll_futex_wake 0x00007ffff6213060                      /lib64/libc.so.6               
libc       lll_futex_wake 0x00007ffff6213060                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
libc       lll_lock_wait_private 0x00007ffff61e5a84                      /lib64/libc.so.6               
libc       lll_lock_wait_private 0x00007ffff61e5a84                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
[...]

That is everything is duplicate for the separate debug info files.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-08 12:38   ` Sergio Durigan Junior
  2011-04-11  3:52     ` Yao Qi
@ 2011-08-12 15:45     ` Jan Kratochvil
  2011-08-12 17:22       ` Frank Ch. Eigler
  1 sibling, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-08-12 15:45 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey

Hi Sergio,

on ppc64 RHEL-6.2pre with rebuilt gdb-7.3.50.20110722-5.fc16 and
systemtap-sdt-devel-1.6-1.el6.ppc64 which contains hopefully recent enough
version of this patch I get:

print $_probe_arg0 == x
Cannot evaluate expression `112(31)'.
(gdb) FAIL: gdb.base/stap-probe.exp: check $_probe_arg0, with semaphore
print $_probe_arg0 == x
Cannot evaluate expression `112(31)'.
(gdb) FAIL: gdb.base/stap-probe.exp: check $_probe_arg0, no semaphore


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-08-12 15:45     ` Jan Kratochvil
@ 2011-08-12 17:22       ` Frank Ch. Eigler
  2011-08-12 21:33         ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Frank Ch. Eigler @ 2011-08-12 17:22 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Sergio Durigan Junior, gdb-patches, Tom Tromey

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> print $_probe_arg0 == x
> Cannot evaluate expression `112(31)'.
> (gdb) FAIL: gdb.base/stap-probe.exp: check $_probe_arg0, with semaphore

That should work, "112(31)" means offset 112 from the address in register 31.

- FChE

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-08-12 17:22       ` Frank Ch. Eigler
@ 2011-08-12 21:33         ` Sergio Durigan Junior
  0 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-08-12 21:33 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: Jan Kratochvil, gdb-patches, Tom Tromey

fche@redhat.com (Frank Ch. Eigler) writes:

> Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
>> print $_probe_arg0 == x
>> Cannot evaluate expression `112(31)'.
>> (gdb) FAIL: gdb.base/stap-probe.exp: check $_probe_arg0, with semaphore
>
> That should work, "112(31)" means offset 112 from the address in register 31.

Yes, it's actually a problem with the parser on stap-probe.c.  I'm
fixing this right now.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH] Implement new `info core mappings' command
@ 2011-10-26 21:08 Sergio Durigan Junior
  2011-10-26 21:25 ` Sergio Durigan Junior
  2011-10-31  0:34 ` Jan Kratochvil
  0 siblings, 2 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-10-26 21:08 UTC (permalink / raw)
  To: gdb-patches

Hello there,

This patch is the revival of:

     http://sourceware.org/ml/gdb-patches/2008-12/msg00322.html

It's been a while since I wanted to work on this again, and hopefully
get it upstream.  I re-read the above thread, tried to address all the
comments, rewrote some things, wrote testcase & doc & NEWS, and that's
it.

What this patch does is implement a new `info' command, called `info
core', and then implement a sub-command called `info core mappings'.
This was heavily based on the existing `info proc mappings'.  The code
iterates over the corefile's sections and, using some heuristics, match
the ones containing useful information for displaying a memory mapping
of the process.  If the corefile section we're examining is empty, then
it tries to search this information at ELF program headers, which is
almost always the used solution.

One thing I am not sure is where to put the entry for this command on
the documentation.  I decided to put it below `info proc', but I'd be
glad if you could give your opinions.

Reviews are welcome, as usual.  Thanks!

Sergio.

2011-10-26  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* NEWS: Mention new `info core mappings' command.
	* corefile.c: Include a bunch of header files needed to implement
	the `info core mappings'.
	(print_proc_map_iter): New function.
	(print_core_map): Likewise.
	(info_core_cmd): Likewise.
	(_initialize_core): Add new `info core' command.

2011-10-26  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.texinfo: Add documentation for `info core mappings'.

2011-10-26  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.base/corefile.exp: Add test for `info core mappings'.

diff --git a/gdb/NEWS b/gdb/NEWS
index 5cdb63e..6f8feaa 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB has a new `info core mappings' command.  It displays the memory
+  regions in a corefile, similar to `info pro mappings' command.
+
 * GDB has two new commands: "set remote hardware-watchpoint-length-limit"
   and "show remote hardware-watchpoint-length-limit".  These allows to
   set or show the maximum length limit (in bytes) of a remote
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..af5a065 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include "inferior.h"
 #include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
 #include "target.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
 #include "gdb_stat.h"
 #include "completer.h"
 #include "exceptions.h"
+#include "objfiles.h"
 
 /* Local function declarations.  */
 
@@ -83,6 +89,186 @@ core_file_command (char *filename, int from_tty)
 }
 \f
 
+/* Helper function for `print_core_map'.  It is used to iterate
+   over the corefile's sections and print proper information about
+   memory-mappings.
+
+   BFD is the bfd used to get the sections.
+   SECT is the current section being "visited".
+   OBJ is not used.  */
+
+static void
+print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
+{
+  /* We're interested in matching sections' names beginning with
+     `load', because they are the sections containing information
+     about the process' memory regions.  */
+  static const char *proc_map_match = "load";
+  int proc_map_match_size = strlen (proc_map_match);
+  /* Flag to indicate whether we have found something.  */
+  int found = 0;
+  /* The section's size.  */
+  bfd_size_type secsize;
+  /* We have to know the bitness of this architecture.  */
+  int bitness;
+  /* We'll use these later.  They are basically used for iterating
+     over every objfile in the system so that we can find needed
+     information about the memory region being examinated.  */
+  struct obj_section *s = NULL;
+  struct objfile *objfile = NULL;
+  /* Fields to be printed for the proc map.  */
+  unsigned long start = 0, end = 0;
+  unsigned int size = 0;
+  char *filename = NULL;
+
+  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+    /* This section is not useful.  */
+    return;
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
+
+  /* Unfortunately, some sections in the corefile don't have any
+     content inside.  This is bad because we need to print, among
+     other things, its final address in the memory (which is
+     impossible to know if we don't have a size).  That's why we
+     first need to check if the section's got anything inside it.  */
+  secsize = bfd_section_size (bfd, sect);
+
+  if (secsize == 0)
+    {
+      /* Ok, the section is empty.  In this case, we must look inside
+	 ELF's Program Header, because (at least) there we have
+	 information about the section's size.  That's what we're doing
+	 here.  */
+      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
+      if (p != NULL)
+	{
+	  int i;
+	  unsigned int n = elf_elfheader (bfd)->e_phnum;
+	  for (i = 0; i < n; i++, p++)
+	    /* For each entry in the Program Header, we have to
+	       check if the section's initial address is equal to
+	       the entry's virtual address.  If it is, then we
+	       have just found the section's entry in the Program
+	       Header, and can use the entry's information to
+	       complete missing data from the section.  */
+	    if (sect->vma == p->p_vaddr)
+	      {
+		found = 1;
+		break;
+	      }
+	  if (found)
+	    secsize = p->p_memsz;
+	}
+    }
+
+  size = secsize;
+  start = sect->vma;
+  end = (unsigned long) (sect->vma + size);
+
+  /* Now begins a new part of the work.  We still don't have complete
+     information about the memory region.  For example, we still need
+     to know the filename which is represented by the region.  Such
+     info can be gathered from the objfile's data structure, and for
+     that we must iterate over all the objsections and check if the
+     objsection's initial address is inside the section we have at hand.
+     If it is, then we can use this specific objsection to obtain the
+     missing data.  */
+  found = 0;
+  ALL_OBJSECTIONS (objfile, s)
+    if (obj_section_addr (s) >= start
+	&& obj_section_addr (s) <= end)
+      {
+	found = 1;
+	break;
+      }
+
+  if (found)
+    filename = s->objfile->name;
+
+  if (bitness == 32)
+    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+  else
+    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+}
+
+/* Implements the `info proc map' command when the user has provided
+   a corefile.  */
+
+static void
+print_core_map (void)
+{
+  const char *exe;
+  int bitness;
+
+  gdb_assert (core_bfd != NULL);
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
+
+  /* Getting the executable name.  */
+  exe = bfd_core_file_failing_command (core_bfd);
+
+  printf_filtered (_("exe = '%s'\n"), exe);
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+  else
+    printf_filtered ("  %18s %18s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+
+  bfd_map_over_sections (core_bfd,
+                         print_proc_map_iter,
+                         NULL);
+}
+
+/* Implement the `info core' command.  */
+
+static void
+info_core_cmd (char *args, int from_tty)
+{
+  char **argv = NULL;
+  int mappings_f = 1;
+  int all = 0;
+
+  if (!core_bfd)
+    error (_("You are not using a corefile at the moment."));
+
+  if (args)
+    {
+      /* Break up 'args' into an argv array.  */
+      argv = gdb_buildargv (args);
+      make_cleanup_freeargv (argv);
+    }
+  while (argv != NULL && *argv != NULL)
+    {
+      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+	{
+	  mappings_f = 1;
+	}
+      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
+	{
+	  all = 1;
+	}
+      argv++;
+    }
+
+  if (mappings_f || all)
+    print_core_map ();
+}
+
 /* If there are two or more functions that wish to hook into
    exec_file_command, this function will call all of the hook
    functions.  */
@@ -450,6 +636,11 @@ _initialize_core (void)
 {
   struct cmd_list_element *c;
 
+  add_info ("core", info_core_cmd, _("\
+Show information about a corefile.\n\
+Specify any of the following keywords for detailed info:\n\
+  mappings -- list of mapped memory regions."));
+
   c = add_cmd ("core-file", class_files, core_file_command, _("\
 Use FILE as core dump for examining memory and registers.\n\
 No arg means have no core file.  This command has been superseded by the\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b451a6a..92e06f3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17655,6 +17655,13 @@ value; etc.  For more information, see the @samp{proc} man page
 Show all the information about the process described under all of the
 above @code{info proc} subcommands.
 
+@kindex info core
+@cindex core dump file
+@item info core
+@item info core mappings
+@cindex memory address space mappings
+Report the memory address space ranges accessible in the core file.
+
 @ignore
 @comment These sub-options of 'info proc' were not included when
 @comment procfs.c was re-written.  Keep their descriptions around
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..190281c 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,13 @@ gdb_test_multiple "x/8bd buf2" "$test" {
     }
 }
 
+# Test the `info core mapping' command.
+set ws "\[ \t\]+"
+set test "test info core mapping"
+gdb_test "info core mapping" \
+	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+	$test
+
 # test reinit_frame_cache
 
 gdb_load ${binfile}

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-26 21:08 [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
@ 2011-10-26 21:25 ` Sergio Durigan Junior
  2011-10-27  7:30   ` Eli Zaretskii
  2011-10-31  0:34 ` Jan Kratochvil
  1 sibling, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-10-26 21:25 UTC (permalink / raw)
  To: gdb-patches

Sergio Durigan Junior <sergiodj@redhat.com> writes:

> Hello there,

I have a theory that you only see errors in your patch when it's already
on the mailing list.

> diff --git a/gdb/NEWS b/gdb/NEWS
> index 5cdb63e..6f8feaa 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,9 @@
>  
>  *** Changes since GDB 7.3.1
>  
> +* GDB has a new `info core mappings' command.  It displays the memory
> +  regions in a corefile, similar to `info pro mappings' command.
                                             ^^^
Typo.

> +static void
> +info_core_cmd (char *args, int from_tty)
> +{
> +  char **argv = NULL;
> +  int mappings_f = 1;
> +  int all = 0;
> +
> +  if (!core_bfd)
> +    error (_("You are not using a corefile at the moment."));
> +
> +  if (args)
> +    {
> +      /* Break up 'args' into an argv array.  */
> +      argv = gdb_buildargv (args);
> +      make_cleanup_freeargv (argv);
> +    }
> +  while (argv != NULL && *argv != NULL)
> +    {
> +      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
> +	{
> +	  mappings_f = 1;
> +	}
> +      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
> +	{
> +	  all = 1;
> +	}
> +      argv++;
> +    }
> +
> +  if (mappings_f || all)
> +    print_core_map ();

Forgot to free `argv'.

Please, consider this new patch.

Thanks,

Sergio.

diff --git a/gdb/NEWS b/gdb/NEWS
index 5cdb63e..d04fbe6 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB has a new `info core mappings' command.  It displays the memory
+  regions in a corefile, similar to `info proc mappings' command.
+
 * GDB has two new commands: "set remote hardware-watchpoint-length-limit"
   and "show remote hardware-watchpoint-length-limit".  These allows to
   set or show the maximum length limit (in bytes) of a remote
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..ab3c6bb 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include "inferior.h"
 #include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
 #include "target.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
 #include "gdb_stat.h"
 #include "completer.h"
 #include "exceptions.h"
+#include "objfiles.h"
 
 /* Local function declarations.  */
 
@@ -83,6 +89,189 @@ core_file_command (char *filename, int from_tty)
 }
 \f
 
+/* Helper function for `print_core_map'.  It is used to iterate
+   over the corefile's sections and print proper information about
+   memory-mappings.
+
+   BFD is the bfd used to get the sections.
+   SECT is the current section being "visited".
+   OBJ is not used.  */
+
+static void
+print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
+{
+  /* We're interested in matching sections' names beginning with
+     `load', because they are the sections containing information
+     about the process' memory regions.  */
+  static const char *proc_map_match = "load";
+  int proc_map_match_size = strlen (proc_map_match);
+  /* Flag to indicate whether we have found something.  */
+  int found = 0;
+  /* The section's size.  */
+  bfd_size_type secsize;
+  /* We have to know the bitness of this architecture.  */
+  int bitness;
+  /* We'll use these later.  They are basically used for iterating
+     over every objfile in the system so that we can find needed
+     information about the memory region being examinated.  */
+  struct obj_section *s = NULL;
+  struct objfile *objfile = NULL;
+  /* Fields to be printed for the proc map.  */
+  unsigned long start = 0, end = 0;
+  unsigned int size = 0;
+  char *filename = NULL;
+
+  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+    /* This section is not useful.  */
+    return;
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
+
+  /* Unfortunately, some sections in the corefile don't have any
+     content inside.  This is bad because we need to print, among
+     other things, its final address in the memory (which is
+     impossible to know if we don't have a size).  That's why we
+     first need to check if the section's got anything inside it.  */
+  secsize = bfd_section_size (bfd, sect);
+
+  if (secsize == 0)
+    {
+      /* Ok, the section is empty.  In this case, we must look inside
+	 ELF's Program Header, because (at least) there we have
+	 information about the section's size.  That's what we're doing
+	 here.  */
+      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
+      if (p != NULL)
+	{
+	  int i;
+	  unsigned int n = elf_elfheader (bfd)->e_phnum;
+	  for (i = 0; i < n; i++, p++)
+	    /* For each entry in the Program Header, we have to
+	       check if the section's initial address is equal to
+	       the entry's virtual address.  If it is, then we
+	       have just found the section's entry in the Program
+	       Header, and can use the entry's information to
+	       complete missing data from the section.  */
+	    if (sect->vma == p->p_vaddr)
+	      {
+		found = 1;
+		break;
+	      }
+	  if (found)
+	    secsize = p->p_memsz;
+	}
+    }
+
+  size = secsize;
+  start = sect->vma;
+  end = (unsigned long) (sect->vma + size);
+
+  /* Now begins a new part of the work.  We still don't have complete
+     information about the memory region.  For example, we still need
+     to know the filename which is represented by the region.  Such
+     info can be gathered from the objfile's data structure, and for
+     that we must iterate over all the objsections and check if the
+     objsection's initial address is inside the section we have at hand.
+     If it is, then we can use this specific objsection to obtain the
+     missing data.  */
+  found = 0;
+  ALL_OBJSECTIONS (objfile, s)
+    if (obj_section_addr (s) >= start
+	&& obj_section_addr (s) <= end)
+      {
+	found = 1;
+	break;
+      }
+
+  if (found)
+    filename = s->objfile->name;
+
+  if (bitness == 32)
+    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+  else
+    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+}
+
+/* Implements the `info proc map' command when the user has provided
+   a corefile.  */
+
+static void
+print_core_map (void)
+{
+  const char *exe;
+  int bitness;
+
+  gdb_assert (core_bfd != NULL);
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
+
+  /* Getting the executable name.  */
+  exe = bfd_core_file_failing_command (core_bfd);
+
+  printf_filtered (_("exe = '%s'\n"), exe);
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+  else
+    printf_filtered ("  %18s %18s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+
+  bfd_map_over_sections (core_bfd,
+                         print_proc_map_iter,
+                         NULL);
+}
+
+/* Implement the `info core' command.  */
+
+static void
+info_core_cmd (char *args, int from_tty)
+{
+  char **argv = NULL;
+  int mappings_f = 1;
+  int all = 0;
+  struct cleanup *c;
+
+  if (!core_bfd)
+    error (_("You are not using a corefile at the moment."));
+
+  if (args)
+    {
+      /* Break up 'args' into an argv array.  */
+      argv = gdb_buildargv (args);
+      c = make_cleanup_freeargv (argv);
+    }
+  while (argv != NULL && *argv != NULL)
+    {
+      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+	{
+	  mappings_f = 1;
+	}
+      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
+	{
+	  all = 1;
+	}
+      argv++;
+    }
+
+  if (mappings_f || all)
+    print_core_map ();
+
+  do_cleanups (c);
+}
+
 /* If there are two or more functions that wish to hook into
    exec_file_command, this function will call all of the hook
    functions.  */
@@ -450,6 +639,11 @@ _initialize_core (void)
 {
   struct cmd_list_element *c;
 
+  add_info ("core", info_core_cmd, _("\
+Show information about a corefile.\n\
+Specify any of the following keywords for detailed info:\n\
+  mappings -- list of mapped memory regions."));
+
   c = add_cmd ("core-file", class_files, core_file_command, _("\
 Use FILE as core dump for examining memory and registers.\n\
 No arg means have no core file.  This command has been superseded by the\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b451a6a..92e06f3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17655,6 +17655,13 @@ value; etc.  For more information, see the @samp{proc} man page
 Show all the information about the process described under all of the
 above @code{info proc} subcommands.
 
+@kindex info core
+@cindex core dump file
+@item info core
+@item info core mappings
+@cindex memory address space mappings
+Report the memory address space ranges accessible in the core file.
+
 @ignore
 @comment These sub-options of 'info proc' were not included when
 @comment procfs.c was re-written.  Keep their descriptions around
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..190281c 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,13 @@ gdb_test_multiple "x/8bd buf2" "$test" {
     }
 }
 
+# Test the `info core mapping' command.
+set ws "\[ \t\]+"
+set test "test info core mapping"
+gdb_test "info core mapping" \
+	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+	$test
+
 # test reinit_frame_cache
 
 gdb_load ${binfile}

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-26 21:25 ` Sergio Durigan Junior
@ 2011-10-27  7:30   ` Eli Zaretskii
  2011-10-27 18:09     ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Eli Zaretskii @ 2011-10-27  7:30 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Wed, 26 Oct 2011 19:07:45 -0200
> 
>  *** Changes since GDB 7.3.1
>  
> +* GDB has a new `info core mappings' command.  It displays the memory
> +  regions in a corefile, similar to `info proc mappings' command.

This is okay.

> +  while (argv != NULL && *argv != NULL)
> +    {
> +      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
> +	{
> +	  mappings_f = 1;
> +	}
> +      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
> +	{
> +	  all = 1;
> +	}
> +      argv++;
> +    }

What is this "all" stuff about?

> +@cindex core dump file

This index entry is too general, it sounds like this section describes
everything about core dump files that GDB supports.  Better qualify
it, e.g.

  @cindex core dump file, list mapped memory

> +@cindex memory address space mappings

Likewise; you need to qualify this so it's clear it only talks about
memory mappings in the context of core file debugging.

> +@item info core
> +@item info core mappings

You cannot have 2 @item's in a row.  All but the first one need to be
@itemx.


> +Report the memory address space ranges accessible in the core file.

I would lose the "space" part.

I think a short example of output would be good here.

> One thing I am not sure is where to put the entry for this command on
> the documentation.  I decided to put it below `info proc', but I'd be
> glad if you could give your opinions.

I don't think it's good to put it in the same section as "info proc",
because we say at the beginning of the section

  Many versions of SVR4 and compatible systems provide a facility called
  @samp{/proc} that can be used to examine the image of a running
  process using file-system subroutines.

But this new command has nothing to do with /proc, and does not need
/proc support to work, right?

If /proc is indeed irrelevant, then I'd prefer a separate @subsection
alongside this one.  You'd need to add some short explanation of the
background and use case(s) for this command, but having that is a good
idea anyway: as written now, this command lands on the reader out of
the blue, more or less.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-27  7:30   ` Eli Zaretskii
@ 2011-10-27 18:09     ` Sergio Durigan Junior
  2011-10-29 19:48       ` Eli Zaretskii
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-10-27 18:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

Hello Eli,

Thanks for the review.

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Date: Wed, 26 Oct 2011 19:07:45 -0200
>> +  while (argv != NULL && *argv != NULL)
>> +    {
>> +      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
>> +	{
>> +	  mappings_f = 1;
>> +	}
>> +      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
>> +	{
>> +	  all = 1;
>> +	}
>> +      argv++;
>> +    }
>
> What is this "all" stuff about?

Removed.  Since it only has 1 valid command (`mappings'), you're right,
we don't need the `all'.

>> +@cindex core dump file
>
> This index entry is too general, it sounds like this section describes
> everything about core dump files that GDB supports.  Better qualify
> it, e.g.
>
>   @cindex core dump file, list mapped memory

Ok, I did my best to rewrite the @cindex using better sentences.  Hope
it's good now.

>> One thing I am not sure is where to put the entry for this command on
>> the documentation.  I decided to put it below `info proc', but I'd be
>> glad if you could give your opinions.
>
> I don't think it's good to put it in the same section as "info proc",
> because we say at the beginning of the section
>
>   Many versions of SVR4 and compatible systems provide a facility called
>   @samp{/proc} that can be used to examine the image of a running
>   process using file-system subroutines.
>
> But this new command has nothing to do with /proc, and does not need
> /proc support to work, right?
>
> If /proc is indeed irrelevant, then I'd prefer a separate @subsection
> alongside this one.  You'd need to add some short explanation of the
> background and use case(s) for this command, but having that is a good
> idea anyway: as written now, this command lands on the reader out of
> the blue, more or less.

Ok, thanks for the directions.  I rewrote this part of the patch (see
below) to address all the comments.  Please, let me know what you think.

Thank you,

Sergio.

diff --git a/gdb/NEWS b/gdb/NEWS
index 5cdb63e..d04fbe6 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB has a new `info core mappings' command.  It displays the memory
+  regions in a corefile, similar to `info proc mappings' command.
+
 * GDB has two new commands: "set remote hardware-watchpoint-length-limit"
   and "show remote hardware-watchpoint-length-limit".  These allows to
   set or show the maximum length limit (in bytes) of a remote
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..3f147f8 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include "inferior.h"
 #include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
 #include "target.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
 #include "gdb_stat.h"
 #include "completer.h"
 #include "exceptions.h"
+#include "objfiles.h"
 
 /* Local function declarations.  */
 
@@ -83,6 +89,185 @@ core_file_command (char *filename, int from_tty)
 }
 \f
 
+/* Helper function for `print_core_map'.  It is used to iterate
+   over the corefile's sections and print proper information about
+   memory-mappings.
+
+   BFD is the bfd used to get the sections.
+   SECT is the current section being "visited".
+   OBJ is not used.  */
+
+static void
+print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
+{
+  /* We're interested in matching sections' names beginning with
+     `load', because they are the sections containing information
+     about the process' memory regions.  */
+  static const char *proc_map_match = "load";
+  int proc_map_match_size = strlen (proc_map_match);
+  /* Flag to indicate whether we have found something.  */
+  int found = 0;
+  /* The section's size.  */
+  bfd_size_type secsize;
+  /* We have to know the bitness of this architecture.  */
+  int bitness;
+  /* We'll use these later.  They are basically used for iterating
+     over every objfile in the system so that we can find needed
+     information about the memory region being examinated.  */
+  struct obj_section *s = NULL;
+  struct objfile *objfile = NULL;
+  /* Fields to be printed for the proc map.  */
+  unsigned long start = 0, end = 0;
+  unsigned int size = 0;
+  char *filename = NULL;
+
+  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+    /* This section is not useful.  */
+    return;
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
+
+  /* Unfortunately, some sections in the corefile don't have any
+     content inside.  This is bad because we need to print, among
+     other things, its final address in the memory (which is
+     impossible to know if we don't have a size).  That's why we
+     first need to check if the section's got anything inside it.  */
+  secsize = bfd_section_size (bfd, sect);
+
+  if (secsize == 0)
+    {
+      /* Ok, the section is empty.  In this case, we must look inside
+	 ELF's Program Header, because (at least) there we have
+	 information about the section's size.  That's what we're doing
+	 here.  */
+      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
+      if (p != NULL)
+	{
+	  int i;
+	  unsigned int n = elf_elfheader (bfd)->e_phnum;
+	  for (i = 0; i < n; i++, p++)
+	    /* For each entry in the Program Header, we have to
+	       check if the section's initial address is equal to
+	       the entry's virtual address.  If it is, then we
+	       have just found the section's entry in the Program
+	       Header, and can use the entry's information to
+	       complete missing data from the section.  */
+	    if (sect->vma == p->p_vaddr)
+	      {
+		found = 1;
+		break;
+	      }
+	  if (found)
+	    secsize = p->p_memsz;
+	}
+    }
+
+  size = secsize;
+  start = sect->vma;
+  end = (unsigned long) (sect->vma + size);
+
+  /* Now begins a new part of the work.  We still don't have complete
+     information about the memory region.  For example, we still need
+     to know the filename which is represented by the region.  Such
+     info can be gathered from the objfile's data structure, and for
+     that we must iterate over all the objsections and check if the
+     objsection's initial address is inside the section we have at hand.
+     If it is, then we can use this specific objsection to obtain the
+     missing data.  */
+  found = 0;
+  ALL_OBJSECTIONS (objfile, s)
+    if (obj_section_addr (s) >= start
+	&& obj_section_addr (s) <= end)
+      {
+	found = 1;
+	break;
+      }
+
+  if (found)
+    filename = s->objfile->name;
+
+  if (bitness == 32)
+    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+  else
+    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+}
+
+/* Implements the `info proc map' command when the user has provided
+   a corefile.  */
+
+static void
+print_core_map (void)
+{
+  const char *exe;
+  int bitness;
+
+  gdb_assert (core_bfd != NULL);
+
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
+
+  /* Getting the executable name.  */
+  exe = bfd_core_file_failing_command (core_bfd);
+
+  printf_filtered (_("exe = '%s'\n"), exe);
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+  else
+    printf_filtered ("  %18s %18s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+
+  bfd_map_over_sections (core_bfd,
+                         print_proc_map_iter,
+                         NULL);
+}
+
+/* Implement the `info core' command.  */
+
+static void
+info_core_cmd (char *args, int from_tty)
+{
+  char **argv = NULL;
+  int mappings_f = 0;
+  struct cleanup *c = NULL;
+
+  if (!core_bfd)
+    error (_("You are not using a corefile at the moment."));
+
+  if (args)
+    {
+      /* Break up 'args' into an argv array.  */
+      argv = gdb_buildargv (args);
+      c = make_cleanup_freeargv (argv);
+    }
+  while (argv != NULL && *argv != NULL)
+    {
+      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+	{
+	  mappings_f = 1;
+	}
+      argv++;
+    }
+
+  if (mappings_f)
+    print_core_map ();
+
+  if (c)
+    do_cleanups (c);
+}
+
 /* If there are two or more functions that wish to hook into
    exec_file_command, this function will call all of the hook
    functions.  */
@@ -450,6 +635,11 @@ _initialize_core (void)
 {
   struct cmd_list_element *c;
 
+  add_info ("core", info_core_cmd, _("\
+Show information about a corefile.\n\
+Specify any of the following keywords for detailed info:\n\
+  mappings -- list of mapped memory regions."));
+
   c = add_cmd ("core-file", class_files, core_file_command, _("\
 Use FILE as core dump for examining memory and registers.\n\
 No arg means have no core file.  This command has been superseded by the\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3e78832..427811e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17713,6 +17713,56 @@ processes and all the threads within each process.
 For QNX Neutrino only, this command displays the list of all mapinfos.
 @end table
 
+@node Process Information from Core Dump File
+@subsection Process Information from Core Dump File
+@cindex examine core dump file process information
+@cindex process info via core dump file
+
+If your system supports the generation of core dump files (core files), you
+can use them to obtain information about processes.  For that, you can use
+the command @code{info core} inside @value{GDBN} to report information like
+the memory mappings of the process when the core dump was generated.
+@code{info core} works only on systems that support core dump files, and only
+when you are using a core dump file inside @value{GDBN}.
+
+@xref{Core File Generation}, for information on how to generate core dump
+files inside @value{GDBN}.  @xref{Files}, for information on invoking
+@value{GDBN} in the post-mortem debugging mode.
+
+@table @code
+@kindex info core
+@cindex core dump file, process information
+@item info core
+@itemx info core mappings
+@cindex memory address space mappings inside a core dump file
+Report the memory address ranges accessible in the core dump file.  Assuming
+you have a core dump file and it is loaded into @value{GDBN}, the output of
+the command will be similar to:
+
+@smallexample
+(@value{GDBP}) info core mappings
+exe = '/tmp/a.out'
+Mapped address spaces:
+
+          Start Addr           End Addr       Size objfile
+            0x400000           0x401000     0x1000 /tmp/a.out
+            0x600000           0x601000     0x1000 /tmp/a.out
+        0x397de00000       0x397de1f000    0x1f000 /usr/lib/debug/lib64/ld-2.13.so.debug
+        0x397e01e000       0x397e01f000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
+        0x397e01f000       0x397e020000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
+        0x397e020000       0x397e021000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
+        0x397e200000       0x397e391000   0x191000 /usr/lib/debug/lib64/libc-2.13.so.debug
+        0x397e591000       0x397e595000     0x4000 /usr/lib/debug/lib64/libc-2.13.so.debug
+        0x397e595000       0x397e596000     0x1000 /usr/lib/debug/lib64/libc-2.13.so.debug
+        0x397e596000       0x397e59c000     0x6000
+      0x7ffff7fd1000     0x7ffff7fd4000     0x3000
+      0x7ffff7ffd000     0x7ffff7ffe000     0x1000
+      0x7ffff7ffe000     0x7ffff7fff000     0x1000 system-supplied DSO at 0x7ffff7ffe000
+      0x7ffffffde000     0x7ffffffff000    0x21000
+  0xffffffffff600000 0xffffffffff601000     0x1000
+@end smallexample
+@end table
+
 @node DJGPP Native
 @subsection Features for Debugging @sc{djgpp} Programs
 @cindex @sc{djgpp} debugging
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..190281c 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,13 @@ gdb_test_multiple "x/8bd buf2" "$test" {
     }
 }
 
+# Test the `info core mapping' command.
+set ws "\[ \t\]+"
+set test "test info core mapping"
+gdb_test "info core mapping" \
+	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+	$test
+
 # test reinit_frame_cache
 
 gdb_load ${binfile}

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-27 18:09     ` Sergio Durigan Junior
@ 2011-10-29 19:48       ` Eli Zaretskii
  0 siblings, 0 replies; 83+ messages in thread
From: Eli Zaretskii @ 2011-10-29 19:48 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 27 Oct 2011 15:55:34 -0200
> 
> Ok, thanks for the directions.  I rewrote this part of the patch (see
> below) to address all the comments.  Please, let me know what you think.

It is fine, except for a single gotcha:

> +@smallexample
> +(@value{GDBP}) info core mappings
> +exe = '/tmp/a.out'
> +Mapped address spaces:
> +
> +          Start Addr           End Addr       Size objfile
> +            0x400000           0x401000     0x1000 /tmp/a.out
> +            0x600000           0x601000     0x1000 /tmp/a.out
> +        0x397de00000       0x397de1f000    0x1f000 /usr/lib/debug/lib64/ld-2.13.so.debug
> +        0x397e01e000       0x397e01f000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
> +        0x397e01f000       0x397e020000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
> +        0x397e020000       0x397e021000     0x1000 /usr/lib/debug/lib64/ld-2.13.so.debug
> +        0x397e200000       0x397e391000   0x191000 /usr/lib/debug/lib64/libc-2.13.so.debug
> +        0x397e591000       0x397e595000     0x4000 /usr/lib/debug/lib64/libc-2.13.so.debug
> +        0x397e595000       0x397e596000     0x1000 /usr/lib/debug/lib64/libc-2.13.so.debug
> +        0x397e596000       0x397e59c000     0x6000
> +      0x7ffff7fd1000     0x7ffff7fd4000     0x3000
> +      0x7ffff7ffd000     0x7ffff7ffe000     0x1000
> +      0x7ffff7ffe000     0x7ffff7fff000     0x1000 system-supplied DSO at 0x7ffff7ffe000
> +      0x7ffffffde000     0x7ffffffff000    0x21000
> +  0xffffffffff600000 0xffffffffff601000     0x1000
> +@end smallexample

This is too wide for a @smallexample, and will overflow the page
limits in print.  We need to keep each line under 75 characters.  So
what I suggest is this:

 . Remove the lines with large addresses from the example, and maybe
   also the line whose "size" is 0x191000

 . Delete as much white space between the columns as possible

 . If the above measures are not enough, shorten the file names of the
   libraries, e.g. /usr/lib/debug/libc.so.debug

Okay with that change.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-26 21:08 [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
  2011-10-26 21:25 ` Sergio Durigan Junior
@ 2011-10-31  0:34 ` Jan Kratochvil
  2011-10-31  7:00   ` Sergio Durigan Junior
  1 sibling, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-10-31  0:34 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Wed, 26 Oct 2011 22:49:53 +0200, Sergio Durigan Junior wrote:
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
[...]
> @@ -83,6 +89,186 @@ core_file_command (char *filename, int from_tty)
>  }
>  \f
>  
> +/* Helper function for `print_core_map'.  It is used to iterate
> +   over the corefile's sections and print proper information about
> +   memory-mappings.
> +
> +   BFD is the bfd used to get the sections.
> +   SECT is the current section being "visited".
> +   OBJ is not used.  */
> +
> +static void
> +print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
> +{
> +  /* We're interested in matching sections' names beginning with
> +     `load', because they are the sections containing information
> +     about the process' memory regions.  */
> +  static const char *proc_map_match = "load";

I think they are pretty useful, for Linux kernel dumped core files with
MMF_DUMP_ELF_HEADERS
/usr/share/doc/kernel-doc-*/Documentation/filesystems/proc.txt
  - (bit 4) ELF header pages in file-backed private memory areas (it is
            effective only if the bit 2 is cleared)

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  NOTE           0x001508 0x0000000000000000 0x0000000000000000 0x0008d0 0x000000     0
  LOAD           0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x008000 R E 0x1000
  LOAD           0x003000 0x0000000000607000 0x0000000000000000 0x002000 0x002000 RW  0x1000

(gdb) info files
Local core dump file:
	0x0000000000400000 - 0x0000000000401000 is load1a
	0x0000000000401000 - 0x0000000000401000 is load1b
	0x0000000000607000 - 0x0000000000609000 is load2

But one does not see the ending address 0x408000 anywhere, one IMO has to use
readelf/objdump now to get the full information.


I think this function should not be based on sections at all, it should just
read the segments.  Linux kernel does not dump any sections.  bfd creates some
some sections from those segments (_bfd_elf_make_section_from_phdr) but they
cannot / do not contain any additional info, those are there IMO only for
better compatibility with sections-only consuming code.

gcore produces even sections but I think it is just redundant info and maybe
even a bug just as a result of the sections generated by bfd.


> +  int proc_map_match_size = strlen (proc_map_match);
> +  /* Flag to indicate whether we have found something.  */
> +  int found = 0;
> +  /* The section's size.  */
> +  bfd_size_type secsize;
> +  /* We have to know the bitness of this architecture.  */
> +  int bitness;
> +  /* We'll use these later.  They are basically used for iterating
> +     over every objfile in the system so that we can find needed
> +     information about the memory region being examinated.  */
> +  struct obj_section *s = NULL;
> +  struct objfile *objfile = NULL;
> +  /* Fields to be printed for the proc map.  */
> +  unsigned long start = 0, end = 0;
> +  unsigned int size = 0;

On 32bit host with --enable-64-bit-bfd: sizeof (bfd_vma) > sizeof (long)
moreover for sizeof (int) of `size'.


> +  char *filename = NULL;
> +
> +  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
> +    /* This section is not useful.  */
> +    return;
> +
> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
> +
> +  /* Unfortunately, some sections in the corefile don't have any
> +     content inside.  This is bad because we need to print, among
> +     other things, its final address in the memory (which is
> +     impossible to know if we don't have a size).  That's why we
> +     first need to check if the section's got anything inside it.  */
> +  secsize = bfd_section_size (bfd, sect);
> +
> +  if (secsize == 0)
> +    {
> +      /* Ok, the section is empty.  In this case, we must look inside
> +	 ELF's Program Header, because (at least) there we have
> +	 information about the section's size.  That's what we're doing
> +	 here.  */
> +      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
> +      if (p != NULL)
> +	{
> +	  int i;
> +	  unsigned int n = elf_elfheader (bfd)->e_phnum;
> +	  for (i = 0; i < n; i++, p++)
> +	    /* For each entry in the Program Header, we have to
> +	       check if the section's initial address is equal to
> +	       the entry's virtual address.  If it is, then we
> +	       have just found the section's entry in the Program
> +	       Header, and can use the entry's information to
> +	       complete missing data from the section.  */
> +	    if (sect->vma == p->p_vaddr)
> +	      {
> +		found = 1;
> +		break;
> +	      }

I do not understand what is a goal of this part.  Isn't it related to the
pairtally omitted segments above?  But those are named "load..." so they are
already skipped.


> +	  if (found)
> +	    secsize = p->p_memsz;
> +	}
> +    }
> +
> +  size = secsize;
> +  start = sect->vma;
> +  end = (unsigned long) (sect->vma + size);
> +
> +  /* Now begins a new part of the work.  We still don't have complete
> +     information about the memory region.  For example, we still need
> +     to know the filename which is represented by the region.  Such
> +     info can be gathered from the objfile's data structure, and for
> +     that we must iterate over all the objsections and check if the
> +     objsection's initial address is inside the section we have at hand.
> +     If it is, then we can use this specific objsection to obtain the
> +     missing data.  */
> +  found = 0;
> +  ALL_OBJSECTIONS (objfile, s)
> +    if (obj_section_addr (s) >= start
> +	&& obj_section_addr (s) <= end)

I think it should ignore S which is section_is_overlay.


> +      {
> +	found = 1;
> +	break;
> +      }
> +
> +  if (found)
> +    filename = s->objfile->name;
> +
> +  if (bitness == 32)
> +    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
> +		     start,
> +		     end,
> +		     (int) size,
> +		     filename ? filename : "");
> +  else
> +    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
> +		     start,
> +		     end,
> +		     (int) size,
> +		     filename ? filename : "");
> +}
> +
> +/* Implements the `info proc map' command when the user has provided
> +   a corefile.  */
> +
> +static void
> +print_core_map (void)
> +{
> +  const char *exe;
> +  int bitness;
> +
> +  gdb_assert (core_bfd != NULL);
> +
> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
> +
> +  /* Getting the executable name.  */
> +  exe = bfd_core_file_failing_command (core_bfd);
> +
> +  printf_filtered (_("exe = '%s'\n"), exe);

bfd_core_file_failing_command can return NULL, NULL is not compatible with %s;
also the bfd error may be printed in such case.


> +  printf_filtered (_("Mapped address spaces:\n\n"));
> +  if (bitness == 32)
> +    printf_filtered ("\t%10s %10s %10s %7s\n",
> +		     "Start Addr",
> +		     "  End Addr",
> +		     "      Size", "objfile");
> +  else
> +    printf_filtered ("  %18s %18s %10s %7s\n",
> +		     "Start Addr",
> +		     "  End Addr",
> +		     "      Size", "objfile");
> +
> +  bfd_map_over_sections (core_bfd,
> +                         print_proc_map_iter,
> +                         NULL);
> +}
> +
> +/* Implement the `info core' command.  */
> +
> +static void
> +info_core_cmd (char *args, int from_tty)
> +{
> +  char **argv = NULL;
> +  int mappings_f = 1;
> +  int all = 0;
> +
> +  if (!core_bfd)
> +    error (_("You are not using a corefile at the moment."));
> +
> +  if (args)
> +    {
> +      /* Break up 'args' into an argv array.  */
> +      argv = gdb_buildargv (args);
> +      make_cleanup_freeargv (argv);
> +    }
> +  while (argv != NULL && *argv != NULL)
> +    {
> +      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
> +	{
> +	  mappings_f = 1;
> +	}
> +      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
> +	{
> +	  all = 1;
> +	}
> +      argv++;
> +    }
> +
> +  if (mappings_f || all)
> +    print_core_map ();
> +}
> +
>  /* If there are two or more functions that wish to hook into
>     exec_file_command, this function will call all of the hook
>     functions.  */
> @@ -450,6 +636,11 @@ _initialize_core (void)
>  {
>    struct cmd_list_element *c;
>  
> +  add_info ("core", info_core_cmd, _("\
> +Show information about a corefile.\n\
> +Specify any of the following keywords for detailed info:\n\
> +  mappings -- list of mapped memory regions."));

I think it should be add_prefix_cmd so that tab completion works.  "mappings
/ "all" should be commands, not parameters.  "info proc" already has this bug.



Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-31  0:34 ` Jan Kratochvil
@ 2011-10-31  7:00   ` Sergio Durigan Junior
  2011-10-31  8:13     ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-10-31  7:00 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Hello Jan,

Thanks for the review.  Comments below.

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> On Wed, 26 Oct 2011 22:49:53 +0200, Sergio Durigan Junior wrote:
>> --- a/gdb/corefile.c
>> +++ b/gdb/corefile.c
> [...]
>> @@ -83,6 +89,186 @@ core_file_command (char *filename, int from_tty)
>>  }
>>  \f
>>  
>> +/* Helper function for `print_core_map'.  It is used to iterate
>> +   over the corefile's sections and print proper information about
>> +   memory-mappings.
>> +
>> +   BFD is the bfd used to get the sections.
>> +   SECT is the current section being "visited".
>> +   OBJ is not used.  */
>> +
>> +static void
>> +print_proc_map_iter (bfd *bfd, asection *sect, void *obj)
>> +{
>> +  /* We're interested in matching sections' names beginning with
>> +     `load', because they are the sections containing information
>> +     about the process' memory regions.  */
>> +  static const char *proc_map_match = "load";
>
> I think they are pretty useful, for Linux kernel dumped core files with
> MMF_DUMP_ELF_HEADERS
> /usr/share/doc/kernel-doc-*/Documentation/filesystems/proc.txt
>   - (bit 4) ELF header pages in file-backed private memory areas (it is
>             effective only if the bit 2 is cleared)
>
> Program Headers:
>   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
>   NOTE           0x001508 0x0000000000000000 0x0000000000000000 0x0008d0 0x000000     0
>   LOAD           0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x008000 R E 0x1000
>   LOAD           0x003000 0x0000000000607000 0x0000000000000000 0x002000 0x002000 RW  0x1000
>
> (gdb) info files
> Local core dump file:
> 	0x0000000000400000 - 0x0000000000401000 is load1a
> 	0x0000000000401000 - 0x0000000000401000 is load1b
> 	0x0000000000607000 - 0x0000000000609000 is load2
>
> But one does not see the ending address 0x408000 anywhere, one IMO has to use
> readelf/objdump now to get the full information.
>
>
> I think this function should not be based on sections at all, it should just
> read the segments.  Linux kernel does not dump any sections.  bfd creates some
> some sections from those segments (_bfd_elf_make_section_from_phdr) but they
> cannot / do not contain any additional info, those are there IMO only for
> better compatibility with sections-only consuming code.

Just to be clear, you're saying that I should actually forget about the
part of the code which checks inside (possible non-empty) sections in
the corefile, and just check immediately for segments?

>> +  int proc_map_match_size = strlen (proc_map_match);
>> +  /* Flag to indicate whether we have found something.  */
>> +  int found = 0;
>> +  /* The section's size.  */
>> +  bfd_size_type secsize;
>> +  /* We have to know the bitness of this architecture.  */
>> +  int bitness;
>> +  /* We'll use these later.  They are basically used for iterating
>> +     over every objfile in the system so that we can find needed
>> +     information about the memory region being examinated.  */
>> +  struct obj_section *s = NULL;
>> +  struct objfile *objfile = NULL;
>> +  /* Fields to be printed for the proc map.  */
>> +  unsigned long start = 0, end = 0;
>> +  unsigned int size = 0;
>
> On 32bit host with --enable-64-bit-bfd: sizeof (bfd_vma) > sizeof (long)
> moreover for sizeof (int) of `size'.

Ok, I'll replace that by unsigned long too, thanks.

>> +  char *filename = NULL;
>> +
>> +  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
>> +    /* This section is not useful.  */
>> +    return;
>> +
>> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (bfd));
>> +
>> +  /* Unfortunately, some sections in the corefile don't have any
>> +     content inside.  This is bad because we need to print, among
>> +     other things, its final address in the memory (which is
>> +     impossible to know if we don't have a size).  That's why we
>> +     first need to check if the section's got anything inside it.  */
>> +  secsize = bfd_section_size (bfd, sect);
>> +
>> +  if (secsize == 0)
>> +    {
>> +      /* Ok, the section is empty.  In this case, we must look inside
>> +	 ELF's Program Header, because (at least) there we have
>> +	 information about the section's size.  That's what we're doing
>> +	 here.  */
>> +      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
>> +      if (p != NULL)
>> +	{
>> +	  int i;
>> +	  unsigned int n = elf_elfheader (bfd)->e_phnum;
>> +	  for (i = 0; i < n; i++, p++)
>> +	    /* For each entry in the Program Header, we have to
>> +	       check if the section's initial address is equal to
>> +	       the entry's virtual address.  If it is, then we
>> +	       have just found the section's entry in the Program
>> +	       Header, and can use the entry's information to
>> +	       complete missing data from the section.  */
>> +	    if (sect->vma == p->p_vaddr)
>> +	      {
>> +		found = 1;
>> +		break;
>> +	      }
>
> I do not understand what is a goal of this part.  Isn't it related to the
> pairtally omitted segments above?  But those are named "load..." so they are
> already skipped.

I'm not sure I understood what you said.  The sections named "load..."
are not skipped.  It's the sections *not* named "load..." which are.

>> +  /* Now begins a new part of the work.  We still don't have complete
>> +     information about the memory region.  For example, we still need
>> +     to know the filename which is represented by the region.  Such
>> +     info can be gathered from the objfile's data structure, and for
>> +     that we must iterate over all the objsections and check if the
>> +     objsection's initial address is inside the section we have at hand.
>> +     If it is, then we can use this specific objsection to obtain the
>> +     missing data.  */
>> +  found = 0;
>> +  ALL_OBJSECTIONS (objfile, s)
>> +    if (obj_section_addr (s) >= start
>> +	&& obj_section_addr (s) <= end)
>
> I think it should ignore S which is section_is_overlay.

You mean I should check for `!section_is_overlay (s)' here?

>> +static void
>> +print_core_map (void)
>> +{
>> +  const char *exe;
>> +  int bitness;
>> +
>> +  gdb_assert (core_bfd != NULL);
>> +
>> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
>> +
>> +  /* Getting the executable name.  */
>> +  exe = bfd_core_file_failing_command (core_bfd);
>> +
>> +  printf_filtered (_("exe = '%s'\n"), exe);
>
> bfd_core_file_failing_command can return NULL, NULL is not compatible with %s;
> also the bfd error may be printed in such case.

Oh, thanks for the catch, I'll update this accordingly.

>> @@ -450,6 +636,11 @@ _initialize_core (void)
>>  {
>>    struct cmd_list_element *c;
>>  
>> +  add_info ("core", info_core_cmd, _("\
>> +Show information about a corefile.\n\
>> +Specify any of the following keywords for detailed info:\n\
>> +  mappings -- list of mapped memory regions."));
>
> I think it should be add_prefix_cmd so that tab completion works.  "mappings
> / "all" should be commands, not parameters.  "info proc" already has this bug.

Yeah, `info proc' is buggy indeed.  I'll see if I send a patch fixing it
tomorrow.  Thanks for the tip.

Thank you,

Sergio.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-31  7:00   ` Sergio Durigan Junior
@ 2011-10-31  8:13     ` Jan Kratochvil
  2011-10-31 12:57       ` Pedro Alves
  2011-11-03 20:01       ` [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
  0 siblings, 2 replies; 83+ messages in thread
From: Jan Kratochvil @ 2011-10-31  8:13 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Mon, 31 Oct 2011 04:16:51 +0100, Sergio Durigan Junior wrote:
> > I think they are pretty useful, for Linux kernel dumped core files with
> > MMF_DUMP_ELF_HEADERS
> > /usr/share/doc/kernel-doc-*/Documentation/filesystems/proc.txt
> >   - (bit 4) ELF header pages in file-backed private memory areas (it is
> >             effective only if the bit 2 is cleared)
> >
> > Program Headers:
> >   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
> >   NOTE           0x001508 0x0000000000000000 0x0000000000000000 0x0008d0 0x000000     0
> >   LOAD           0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x008000 R E 0x1000
> >   LOAD           0x003000 0x0000000000607000 0x0000000000000000 0x002000 0x002000 RW  0x1000
> >
> > (gdb) info files
> > Local core dump file:
> > 	0x0000000000400000 - 0x0000000000401000 is load1a
> > 	0x0000000000401000 - 0x0000000000401000 is load1b
> > 	0x0000000000607000 - 0x0000000000609000 is load2
> >
> > But one does not see the ending address 0x408000 anywhere, one IMO has to use
> > readelf/objdump now to get the full information.
> >
> >
> > I think this function should not be based on sections at all, it should just
> > read the segments.  Linux kernel does not dump any sections.  bfd creates some
> > some sections from those segments (_bfd_elf_make_section_from_phdr) but they
> > cannot / do not contain any additional info, those are there IMO only for
> > better compatibility with sections-only consuming code.
> 
> Just to be clear, you're saying that I should actually forget about the
> part of the code which checks inside (possible non-empty) sections in
> the corefile, and just check immediately for segments?

Yes.  Otherwise you need the tricks combining it with segments you do below
anyway, moreover you can read in sections in core file generated by gcore
which are completely useless,


> >> +  /* Fields to be printed for the proc map.  */
> >> +  unsigned long start = 0, end = 0;
> >> +  unsigned int size = 0;
> >
> > On 32bit host with --enable-64-bit-bfd: sizeof (bfd_vma) > sizeof (long)
> > moreover for sizeof (int) of `size'.
> 
> Ok, I'll replace that by unsigned long too, thanks.

I meant you should use bfd_vma.  Even `unsigned long' is too short.  You would
need to use `unsigned long long' but that has compatibility issues already
resolved if you just use `bfd_vma'.


> >> +  /* Unfortunately, some sections in the corefile don't have any
> >> +     content inside.  This is bad because we need to print, among
> >> +     other things, its final address in the memory (which is
> >> +     impossible to know if we don't have a size).  That's why we
> >> +     first need to check if the section's got anything inside it.  */
> >> +  secsize = bfd_section_size (bfd, sect);
> >> +
> >> +  if (secsize == 0)
> >> +    {
> >> +      /* Ok, the section is empty.  In this case, we must look inside
> >> +	 ELF's Program Header, because (at least) there we have
> >> +	 information about the section's size.  That's what we're doing
> >> +	 here.  */
> >> +      Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr;
> >> +      if (p != NULL)
> >> +	{
> >> +	  int i;
> >> +	  unsigned int n = elf_elfheader (bfd)->e_phnum;
> >> +	  for (i = 0; i < n; i++, p++)
> >> +	    /* For each entry in the Program Header, we have to
> >> +	       check if the section's initial address is equal to
> >> +	       the entry's virtual address.  If it is, then we
> >> +	       have just found the section's entry in the Program
> >> +	       Header, and can use the entry's information to
> >> +	       complete missing data from the section.  */
> >> +	    if (sect->vma == p->p_vaddr)
> >> +	      {
> >> +		found = 1;
> >> +		break;
> >> +	      }
> >
> > I do not understand what is a goal of this part.  Isn't it related to the
> > pairtally omitted segments above?  But those are named "load..." so they are
> > already skipped.
> 
> I'm not sure I understood what you said.  The sections named "load..."
> are not skipped.  It's the sections *not* named "load..." which are.

Sorry, OK.  But still I do not understand why to look at sections of core file
at all.  Another question is to handle non-ELF core files but that could be
a completely separate code path.


> 
> >> +  ALL_OBJSECTIONS (objfile, s)
> >> +    if (obj_section_addr (s) >= start
> >> +	&& obj_section_addr (s) <= end)
> >
> > I think it should ignore S which is section_is_overlay.
> 
> You mean I should check for `!section_is_overlay (s)' here?

Yes.


> >> @@ -450,6 +636,11 @@ _initialize_core (void)
> >>  {
> >>    struct cmd_list_element *c;
> >>  
> >> +  add_info ("core", info_core_cmd, _("\
> >> +Show information about a corefile.\n\
> >> +Specify any of the following keywords for detailed info:\n\
> >> +  mappings -- list of mapped memory regions."));
> >
> > I think it should be add_prefix_cmd so that tab completion works.  "mappings
> > / "all" should be commands, not parameters.  "info proc" already has this bug.
> 
> Yeah, `info proc' is buggy indeed.  I'll see if I send a patch fixing it
> tomorrow.  Thanks for the tip.

Or it should be a single command using add_setshow_enum_cmd, not sure which
approach is better.  Still I think the separate commands are better as they
can have each specific help text.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-31  8:13     ` Jan Kratochvil
@ 2011-10-31 12:57       ` Pedro Alves
  2011-11-01 11:54         ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Jan Kratochvil
  2011-11-03 20:01       ` [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2011-10-31 12:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil, Sergio Durigan Junior

[-- Attachment #1: Type: Text/Plain, Size: 843 bytes --]

On Monday 31 October 2011 07:00:12, Jan Kratochvil wrote:

> > > I think it should be add_prefix_cmd so that tab completion works.  "mappings
> > > / "all" should be commands, not parameters.  "info proc" already has this bug.
> > 
> > Yeah, `info proc' is buggy indeed.  I'll see if I send a patch fixing it
> > tomorrow.  Thanks for the tip.
> 
> Or it should be a single command using add_setshow_enum_cmd, not sure which
> approach is better.  Still I think the separate commands are better as they
> can have each specific help text.

I once wrote a patch for that.   /me *looks for it*
The reason I never pushed it is that "info proc" handles
more than one keyword at the same time.  E.g.,
"info proc cmdline cwd" displays both cmdline and cwd
info simultaneously.  That doesn't work if you have a 
command per keyword.

-- 
Pedro Alves

[-- Attachment #2: proc_map.diff --]
[-- Type: text/x-patch, Size: 6614 bytes --]

2010-04-14  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* linux-nat.c (info_proc_cmdlist): New.
	(info_proc_command): New.
	(_initialize_linux_nat): Install `info mappings', `info stat `,
	info proc stat', `info proc status' and `info proc all' as real
	subcommands of `info proc'.

---
 gdb/linux-nat.c |  182 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 119 insertions(+), 63 deletions(-)

Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2010-04-14 17:49:17.000000000 +0100
+++ src/gdb/linux-nat.c	2010-04-14 19:18:55.000000000 +0100
@@ -4429,72 +4429,43 @@ linux_nat_make_corefile_notes (bfd *obfd
 
 /* Implement the "info proc" command.  */
 
+enum info_proc_what
+  {
+    IP_MINIMAL = 0,
+
+    IP_MAPPINGS = 1,
+    IP_STATUS,
+    IP_STAT,
+    IP_CMDLINE,
+    IP_EXE,
+    IP_ENVIRON,
+    IP_CWD,
+
+    IP_ALL = -1
+  };
+
 static void
-linux_nat_info_proc_cmd (char *args, int from_tty)
+linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
   long pid = PIDGET (inferior_ptid);
   FILE *procfile;
-  char **argv = NULL;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
-  int cmdline_f = 1;
-  int cwd_f = 1;
-  int exe_f = 1;
-  int mappings_f = 0;
-  int environ_f = 0;
-  int status_f = 0;
-  int stat_f = 0;
-  int all = 0;
+  int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE);
+  int cwd_f = (what == IP_MINIMAL || what == IP_CWD);
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE);
+  int mappings_f = (what == IP_MAPPINGS);
+  int environ_f = (what == IP_ENVIRON);
+  int status_f = (what == IP_STATUS);
+  int stat_f =  (what == IP_STAT);
+  int all = (what == IP_ALL);
   struct stat dummy;
 
-  if (args)
-    {
-      /* Break up 'args' into an argv array.  */
-      argv = gdb_buildargv (args);
-      make_cleanup_freeargv (argv);
-    }
-  while (argv != NULL && *argv != NULL)
-    {
-      if (isdigit (argv[0][0]))
-	{
-	  pid = strtoul (argv[0], NULL, 10);
-	}
-      else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
-	{
-	  mappings_f = 1;
-	}
-      else if (strcmp (argv[0], "status") == 0)
-	{
-	  status_f = 1;
-	}
-      else if (strcmp (argv[0], "stat") == 0)
-	{
-	  stat_f = 1;
-	}
-      else if (strcmp (argv[0], "cmd") == 0)
-	{
-	  cmdline_f = 1;
-	}
-      else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
-	{
-	  exe_f = 1;
-	}
-      else if (strcmp (argv[0], "cwd") == 0)
-	{
-	  cwd_f = 1;
-	}
-      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
-	{
-	  all = 1;
-	}
-      else
-	{
-	  /* [...] (future options here) */
-	}
-      argv++;
-    }
+  if (args && isdigit (args[0]))
+    pid = strtoul (args, NULL, 10);
+
   if (pid == 0)
     error (_("No current process: you must name one."));
 
@@ -4710,6 +4681,60 @@ linux_nat_info_proc_cmd (char *args, int
     }
 }
 
+static void
+linux_nat_info_proc_cmd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_mappings (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_stat (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STAT, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_status (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STATUS, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_cwd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CWD, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_cmdline (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_exe (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_EXE, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_environ (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_ENVIRON, from_tty);
+}
+
+static void
+linux_nat_info_proc_cmd_all (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_ALL, from_tty);
+}
+
 /* Implement the to_xfer_partial interface for memory reads using the /proc
    filesystem.  Because we can use a single read() call for /proc, this
    can be much more efficient than banging away at PTRACE_PEEKTEXT,
@@ -5624,16 +5649,47 @@ extern initialize_file_ftype _initialize
 void
 _initialize_linux_nat (void)
 {
+  static struct cmd_list_element *info_proc_cmdlist;
   sigset_t mask;
 
-  add_info ("proc", linux_nat_info_proc_cmd, _("\
+  add_prefix_cmd ("proc", class_info, linux_nat_info_proc_cmd,
+		  _("\
 Show /proc process information about any running process.\n\
-Specify any process id, or use the program being debugged by default.\n\
-Specify any of the following keywords for detailed info:\n\
-  mappings -- list of mapped memory regions.\n\
-  stat     -- list a bunch of random process info.\n\
-  status   -- list a different bunch of random process info.\n\
-  all      -- list all available /proc info."));
+Specify any process id, or use the program being debugged by default."),
+		  &info_proc_cmdlist, "info proc ",
+		  1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
+List of mapped memory regions."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
+List a bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("environ", class_info, linux_nat_info_proc_cmd_environ, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\
+List all available /proc info."),
+	   &info_proc_cmdlist);
 
   add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
 			    &debug_linux_nat, _("\

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [patch] `info proc ' completion  [Re: [PATCH] Implement new `info core mappings' command]
  2011-10-31 12:57       ` Pedro Alves
@ 2011-11-01 11:54         ` Jan Kratochvil
  2011-11-01 16:23           ` Eli Zaretskii
  2011-11-02 18:30           ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Pedro Alves
  0 siblings, 2 replies; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-01 11:54 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Sergio Durigan Junior

On Mon, 31 Oct 2011 13:20:53 +0100, Pedro Alves wrote:
> I once wrote a patch for that.   /me *looks for it*

Rebased and cleaned up the diff.


> The reason I never pushed it is that "info proc" handles
> more than one keyword at the same time.  E.g.,
> "info proc cmdline cwd" displays both cmdline and cwd
> info simultaneously.  That doesn't work if you have a 
> command per keyword.

I did not know that, the doc does not mention it and such feature is very
easily "workaroundable", I do not think it can be compared to he inconvenience
of the current state.

OTOH I do not understand what is it good for when one has shell but if the
feature is already there...

No regressions on {x86_64,x86_64-m32,i686}-fedora16pre-linux-gnu.


Thanks,
Jan


gdb/
2011-11-01  Pedro Alves  <pedro@codesourcery.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	* linux-nat.c (enum info_proc_what): New.
	(linux_nat_info_proc_cmd): Rename to ...
	(linux_nat_info_proc_cmd_1): ... here.  Remove variables argv and all.
	New parameter what.  Initialize cmdline_f, cwd_f, exe_f, mappings_f,
	status_f and stat_f from WHAT.  Throw error on extra parameters.
	(linux_nat_info_proc_cmd, linux_nat_info_proc_cmd_mappings)
	(linux_nat_info_proc_cmd_stat, linux_nat_info_proc_cmd_status)
	(linux_nat_info_proc_cmd_cwd, linux_nat_info_proc_cmd_cmdline)
	(linux_nat_info_proc_cmd_exe, linux_nat_info_proc_cmd_all): New.
	(_initialize_linux_nat): New variable info_proc_cmdlist.  Install `info
	proc mappings', `info proc stat`, `info proc status', `info proc cwd',
	`info proc cmdline', `info proc exe' and `info proc all' as real
	subcommands of `info proc'.

--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4746,71 +4746,58 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 
 /* Implement the "info proc" command.  */
 
+enum info_proc_what
+  {
+    /* Display the default cmdline, cwd and exe outputs.  */
+    IP_MINIMAL,
+
+    /* Display `info proc mappings'.  */
+    IP_MAPPINGS,
+
+    /* Display `info proc status'.  */
+    IP_STATUS,
+
+    /* Display `info proc stat'.  */
+    IP_STAT,
+
+    /* Display `info proc cmdline'.  */
+    IP_CMDLINE,
+
+    /* Display `info proc exe'.  */
+    IP_EXE,
+
+    /* Display `info proc cwd'.  */
+    IP_CWD,
+
+    /* Display all of the above.  */
+    IP_ALL
+  };
+
 static void
-linux_nat_info_proc_cmd (char *args, int from_tty)
+linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
   long pid = PIDGET (inferior_ptid);
   FILE *procfile;
-  char **argv = NULL;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
-  int cmdline_f = 1;
-  int cwd_f = 1;
-  int exe_f = 1;
-  int mappings_f = 0;
-  int status_f = 0;
-  int stat_f = 0;
-  int all = 0;
+  int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
+  int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+  int status_f = (what == IP_STATUS || what == IP_ALL);
+  int stat_f =  (what == IP_STAT || what == IP_ALL);
   struct stat dummy;
 
-  if (args)
-    {
-      /* Break up 'args' into an argv array.  */
-      argv = gdb_buildargv (args);
-      make_cleanup_freeargv (argv);
-    }
-  while (argv != NULL && *argv != NULL)
-    {
-      if (isdigit (argv[0][0]))
-	{
-	  pid = strtoul (argv[0], NULL, 10);
-	}
-      else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
-	{
-	  mappings_f = 1;
-	}
-      else if (strcmp (argv[0], "status") == 0)
-	{
-	  status_f = 1;
-	}
-      else if (strcmp (argv[0], "stat") == 0)
-	{
-	  stat_f = 1;
-	}
-      else if (strcmp (argv[0], "cmd") == 0)
-	{
-	  cmdline_f = 1;
-	}
-      else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
-	{
-	  exe_f = 1;
-	}
-      else if (strcmp (argv[0], "cwd") == 0)
-	{
-	  cwd_f = 1;
-	}
-      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
-	{
-	  all = 1;
-	}
-      else
-	{
-	  /* [...] (future options here).  */
-	}
-      argv++;
-    }
+  if (args && isdigit (args[0]))
+    pid = strtoul (args, &args, 10);
+
+  while (args && isspace (*args))
+    args++;
+  if (args && args[0])
+    error (_("Too many parameters: %s"), args);
+
   if (pid == 0)
     error (_("No current process: you must name one."));
 
@@ -4819,7 +4806,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     error (_("No /proc directory: '%s'"), fname1);
 
   printf_filtered (_("process %ld\n"), pid);
-  if (cmdline_f || all)
+  if (cmdline_f)
     {
       sprintf (fname1, "/proc/%ld/cmdline", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4835,7 +4822,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (cwd_f || all)
+  if (cwd_f)
     {
       sprintf (fname1, "/proc/%ld/cwd", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4844,7 +4831,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
 	warning (_("unable to read link '%s'"), fname1);
     }
-  if (exe_f || all)
+  if (exe_f)
     {
       sprintf (fname1, "/proc/%ld/exe", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4853,7 +4840,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
 	warning (_("unable to read link '%s'"), fname1);
     }
-  if (mappings_f || all)
+  if (mappings_f)
     {
       sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4915,7 +4902,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (status_f || all)
+  if (status_f)
     {
       sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4929,7 +4916,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (stat_f || all)
+  if (stat_f)
     {
       sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -5029,6 +5016,70 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
 }
 
+/* Implement `info proc' when given without any futher parameters.  */
+
+static void
+linux_nat_info_proc_cmd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
+}
+
+/* Implement `info proc mappings'.  */
+
+static void
+linux_nat_info_proc_cmd_mappings (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
+}
+
+/* Implement `info proc stat'.  */
+
+static void
+linux_nat_info_proc_cmd_stat (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STAT, from_tty);
+}
+
+/* Implement `info proc status'.  */
+
+static void
+linux_nat_info_proc_cmd_status (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STATUS, from_tty);
+}
+
+/* Implement `info proc cwd'.  */
+
+static void
+linux_nat_info_proc_cmd_cwd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CWD, from_tty);
+}
+
+/* Implement `info proc cmdline'.  */
+
+static void
+linux_nat_info_proc_cmd_cmdline (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
+}
+
+/* Implement `info proc exe'.  */
+
+static void
+linux_nat_info_proc_cmd_exe (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_EXE, from_tty);
+}
+
+/* Implement `info proc all'.  */
+
+static void
+linux_nat_info_proc_cmd_all (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_ALL, from_tty);
+}
+
 /* Implement the to_xfer_partial interface for memory reads using the /proc
    filesystem.  Because we can use a single read() call for /proc, this
    can be much more efficient than banging away at PTRACE_PEEKTEXT,
@@ -5822,14 +5873,42 @@ extern initialize_file_ftype _initialize_linux_nat;
 void
 _initialize_linux_nat (void)
 {
-  add_info ("proc", linux_nat_info_proc_cmd, _("\
+  static struct cmd_list_element *info_proc_cmdlist;
+
+  add_prefix_cmd ("proc", class_info, linux_nat_info_proc_cmd,
+		  _("\
 Show /proc process information about any running process.\n\
-Specify any process id, or use the program being debugged by default.\n\
-Specify any of the following keywords for detailed info:\n\
-  mappings -- list of mapped memory regions.\n\
-  stat     -- list a bunch of random process info.\n\
-  status   -- list a different bunch of random process info.\n\
-  all      -- list all available /proc info."));
+Specify any process id, or use the program being debugged by default."),
+		  &info_proc_cmdlist, "info proc ",
+		  1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
+List of mapped memory regions."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
+List a bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\
+List all available /proc info."),
+	   &info_proc_cmdlist);
 
   add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
 			    &debug_linux_nat, _("\

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc ' completion  [Re: [PATCH] Implement new `info core mappings' command]
  2011-11-01 11:54         ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Jan Kratochvil
@ 2011-11-01 16:23           ` Eli Zaretskii
  2011-11-03 14:12             ` [patch] `info proc *' help fix [Re: [patch] `info proc ' completion] Jan Kratochvil
  2011-11-02 18:30           ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Pedro Alves
  1 sibling, 1 reply; 83+ messages in thread
From: Eli Zaretskii @ 2011-11-01 16:23 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: pedro, gdb-patches, sergiodj

> Date: Tue, 1 Nov 2011 12:54:05 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: gdb-patches@sourceware.org, Sergio Durigan Junior <sergiodj@redhat.com>
> 
> -Specify any process id, or use the program being debugged by default.\n\
> -Specify any of the following keywords for detailed info:\n\
> -  mappings -- list of mapped memory regions.\n\
> -  stat     -- list a bunch of random process info.\n\
> -  status   -- list a different bunch of random process info.\n\
> -  all      -- list all available /proc info."));
> +Specify any process id, or use the program being debugged by default."),
> +		  &info_proc_cmdlist, "info proc ",
> +		  1/*allow-unknown*/, &infolist);
> +
> +  add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
> +List of mapped memory regions."),
> +	   &info_proc_cmdlist);
> +
> +  add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
> +List a bunch of random process info."),
> +	   &info_proc_cmdlist);
> +
> +  add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
> +List a different bunch of random process info."),
> +	   &info_proc_cmdlist);
> +
> +  add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
> +List a different bunch of random process info."),
> +	   &info_proc_cmdlist);
> +
> +  add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
> +List a different bunch of random process info."),
> +	   &info_proc_cmdlist);
> +
> +  add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
> +List a different bunch of random process info."),

I wonder if we could clean up this mess with 5 "different bunches of
info", while we are at that.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc ' completion  [Re: [PATCH] Implement new `info core mappings' command]
  2011-11-01 11:54         ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Jan Kratochvil
  2011-11-01 16:23           ` Eli Zaretskii
@ 2011-11-02 18:30           ` Pedro Alves
  2011-11-02 18:48             ` [commit] " Jan Kratochvil
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2011-11-02 18:30 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, Sergio Durigan Junior

On Tuesday 01 November 2011 11:54:05, Jan Kratochvil wrote:
> On Mon, 31 Oct 2011 13:20:53 +0100, Pedro Alves wrote:
> > I once wrote a patch for that.   /me *looks for it*
> 
> Rebased and cleaned up the diff.
> 
> 
> > The reason I never pushed it is that "info proc" handles
> > more than one keyword at the same time.  E.g.,
> > "info proc cmdline cwd" displays both cmdline and cwd
> > info simultaneously.  That doesn't work if you have a 
> > command per keyword.
> 
> I did not know that, the doc does not mention it and such feature is very
> easily "workaroundable", I do not think it can be compared to he inconvenience
> of the current state.

I agree.

> OTOH I do not understand what is it good for when one has shell but if the
> feature is already there...

Yeah...

> +  int stat_f =  (what == IP_STAT || what == IP_ALL);

Extra space.

> +  while (args && isspace (*args))
> +    args++;

args = skip_spaces (args);

> +  if (args && args[0])
> +    error (_("Too many parameters: %s"), args);

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [commit] [patch] `info proc ' completion  [Re: [PATCH] Implement new `info core mappings' command]
  2011-11-02 18:30           ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Pedro Alves
@ 2011-11-02 18:48             ` Jan Kratochvil
  0 siblings, 0 replies; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-02 18:48 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Sergio Durigan Junior

On Wed, 02 Nov 2011 19:30:37 +0100, Pedro Alves wrote:
> > +  while (args && isspace (*args))
> > +    args++;
> 
> args = skip_spaces (args);

oops


Checked in.


Thanks,
Jan


http://sourceware.org/ml/gdb-cvs/2011-11/msg00012.html

--- src/gdb/ChangeLog	2011/11/02 04:12:50	1.13480
+++ src/gdb/ChangeLog	2011/11/02 18:47:15	1.13481
@@ -1,3 +1,21 @@
+2011-11-02  Pedro Alves  <pedro@codesourcery.com>
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* linux-nat.c: Include cli/cli-utils.h.
+	(enum info_proc_what): New.
+	(linux_nat_info_proc_cmd): Rename to ...
+	(linux_nat_info_proc_cmd_1): ... here.  Remove variables argv and all.
+	New parameter what.  Initialize cmdline_f, cwd_f, exe_f, mappings_f,
+	status_f and stat_f from WHAT.  Throw error on extra parameters.
+	(linux_nat_info_proc_cmd, linux_nat_info_proc_cmd_mappings)
+	(linux_nat_info_proc_cmd_stat, linux_nat_info_proc_cmd_status)
+	(linux_nat_info_proc_cmd_cwd, linux_nat_info_proc_cmd_cmdline)
+	(linux_nat_info_proc_cmd_exe, linux_nat_info_proc_cmd_all): New.
+	(_initialize_linux_nat): New variable info_proc_cmdlist.  Install `info
+	proc mappings', `info proc stat`, `info proc status', `info proc cwd',
+	`info proc cmdline', `info proc exe' and `info proc all' as real
+	subcommands of `info proc'.
+
 2011-11-01  Justin Lebar  <justin.lebar@gmail.com>
 
 	* Makefile.in: (SFILES): Add skip.c.
--- src/gdb/linux-nat.c	2011/10/28 18:29:59	1.225
+++ src/gdb/linux-nat.c	2011/11/02 18:47:16	1.226
@@ -59,6 +59,7 @@
 #include <sys/vfs.h>
 #include "solib.h"
 #include "linux-osdata.h"
+#include "cli/cli-utils.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -4746,71 +4747,57 @@
 
 /* Implement the "info proc" command.  */
 
+enum info_proc_what
+  {
+    /* Display the default cmdline, cwd and exe outputs.  */
+    IP_MINIMAL,
+
+    /* Display `info proc mappings'.  */
+    IP_MAPPINGS,
+
+    /* Display `info proc status'.  */
+    IP_STATUS,
+
+    /* Display `info proc stat'.  */
+    IP_STAT,
+
+    /* Display `info proc cmdline'.  */
+    IP_CMDLINE,
+
+    /* Display `info proc exe'.  */
+    IP_EXE,
+
+    /* Display `info proc cwd'.  */
+    IP_CWD,
+
+    /* Display all of the above.  */
+    IP_ALL
+  };
+
 static void
-linux_nat_info_proc_cmd (char *args, int from_tty)
+linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
   long pid = PIDGET (inferior_ptid);
   FILE *procfile;
-  char **argv = NULL;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
-  int cmdline_f = 1;
-  int cwd_f = 1;
-  int exe_f = 1;
-  int mappings_f = 0;
-  int status_f = 0;
-  int stat_f = 0;
-  int all = 0;
+  int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
+  int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+  int status_f = (what == IP_STATUS || what == IP_ALL);
+  int stat_f = (what == IP_STAT || what == IP_ALL);
   struct stat dummy;
 
-  if (args)
-    {
-      /* Break up 'args' into an argv array.  */
-      argv = gdb_buildargv (args);
-      make_cleanup_freeargv (argv);
-    }
-  while (argv != NULL && *argv != NULL)
-    {
-      if (isdigit (argv[0][0]))
-	{
-	  pid = strtoul (argv[0], NULL, 10);
-	}
-      else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
-	{
-	  mappings_f = 1;
-	}
-      else if (strcmp (argv[0], "status") == 0)
-	{
-	  status_f = 1;
-	}
-      else if (strcmp (argv[0], "stat") == 0)
-	{
-	  stat_f = 1;
-	}
-      else if (strcmp (argv[0], "cmd") == 0)
-	{
-	  cmdline_f = 1;
-	}
-      else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
-	{
-	  exe_f = 1;
-	}
-      else if (strcmp (argv[0], "cwd") == 0)
-	{
-	  cwd_f = 1;
-	}
-      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
-	{
-	  all = 1;
-	}
-      else
-	{
-	  /* [...] (future options here).  */
-	}
-      argv++;
-    }
+  if (args && isdigit (args[0]))
+    pid = strtoul (args, &args, 10);
+
+  args = skip_spaces (args);
+  if (args && args[0])
+    error (_("Too many parameters: %s"), args);
+
   if (pid == 0)
     error (_("No current process: you must name one."));
 
@@ -4819,7 +4806,7 @@
     error (_("No /proc directory: '%s'"), fname1);
 
   printf_filtered (_("process %ld\n"), pid);
-  if (cmdline_f || all)
+  if (cmdline_f)
     {
       sprintf (fname1, "/proc/%ld/cmdline", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4835,7 +4822,7 @@
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (cwd_f || all)
+  if (cwd_f)
     {
       sprintf (fname1, "/proc/%ld/cwd", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4844,7 +4831,7 @@
       else
 	warning (_("unable to read link '%s'"), fname1);
     }
-  if (exe_f || all)
+  if (exe_f)
     {
       sprintf (fname1, "/proc/%ld/exe", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4853,7 +4840,7 @@
       else
 	warning (_("unable to read link '%s'"), fname1);
     }
-  if (mappings_f || all)
+  if (mappings_f)
     {
       sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4915,7 +4902,7 @@
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (status_f || all)
+  if (status_f)
     {
       sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4929,7 +4916,7 @@
       else
 	warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (stat_f || all)
+  if (stat_f)
     {
       sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -5029,6 +5016,70 @@
     }
 }
 
+/* Implement `info proc' when given without any futher parameters.  */
+
+static void
+linux_nat_info_proc_cmd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
+}
+
+/* Implement `info proc mappings'.  */
+
+static void
+linux_nat_info_proc_cmd_mappings (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
+}
+
+/* Implement `info proc stat'.  */
+
+static void
+linux_nat_info_proc_cmd_stat (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STAT, from_tty);
+}
+
+/* Implement `info proc status'.  */
+
+static void
+linux_nat_info_proc_cmd_status (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STATUS, from_tty);
+}
+
+/* Implement `info proc cwd'.  */
+
+static void
+linux_nat_info_proc_cmd_cwd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CWD, from_tty);
+}
+
+/* Implement `info proc cmdline'.  */
+
+static void
+linux_nat_info_proc_cmd_cmdline (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
+}
+
+/* Implement `info proc exe'.  */
+
+static void
+linux_nat_info_proc_cmd_exe (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_EXE, from_tty);
+}
+
+/* Implement `info proc all'.  */
+
+static void
+linux_nat_info_proc_cmd_all (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_ALL, from_tty);
+}
+
 /* Implement the to_xfer_partial interface for memory reads using the /proc
    filesystem.  Because we can use a single read() call for /proc, this
    can be much more efficient than banging away at PTRACE_PEEKTEXT,
@@ -5822,14 +5873,42 @@
 void
 _initialize_linux_nat (void)
 {
-  add_info ("proc", linux_nat_info_proc_cmd, _("\
+  static struct cmd_list_element *info_proc_cmdlist;
+
+  add_prefix_cmd ("proc", class_info, linux_nat_info_proc_cmd,
+		  _("\
 Show /proc process information about any running process.\n\
-Specify any process id, or use the program being debugged by default.\n\
-Specify any of the following keywords for detailed info:\n\
-  mappings -- list of mapped memory regions.\n\
-  stat     -- list a bunch of random process info.\n\
-  status   -- list a different bunch of random process info.\n\
-  all      -- list all available /proc info."));
+Specify any process id, or use the program being debugged by default."),
+		  &info_proc_cmdlist, "info proc ",
+		  1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
+List of mapped memory regions."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
+List a bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
+List a different bunch of random process info."),
+	   &info_proc_cmdlist);
+
+  add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\
+List all available /proc info."),
+	   &info_proc_cmdlist);
 
   add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
 			    &debug_linux_nat, _("\

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [patch] `info proc *' help fix  [Re: [patch] `info proc ' completion]
  2011-11-01 16:23           ` Eli Zaretskii
@ 2011-11-03 14:12             ` Jan Kratochvil
  2011-11-03 16:57               ` Eli Zaretskii
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-03 14:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pedro, gdb-patches, sergiodj

On Tue, 01 Nov 2011 17:22:42 +0100, Eli Zaretskii wrote:
> I wonder if we could clean up this mess with 5 "different bunches of
> info", while we are at that.

Sorry I somehow mishandled your mail, OK this way?

No regressions on {x86_64,x86_64-m32,i686}-fedora16pre-linux-gnu.


Thanks,
Jan


gdb/
2011-11-03  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* linux-nat.c (_initialize_linux_nat): Improve help
	for `info proc stat', `info proc status', `info proc cwd',
	`info proc cmdline' and `info proc exe'.

--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -5887,23 +5887,23 @@ List of mapped memory regions."),
 	   &info_proc_cmdlist);
 
   add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
-List a bunch of random process info."),
+List annotated random process info from /proc/PID/stat."),
 	   &info_proc_cmdlist);
 
   add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
-List a different bunch of random process info."),
+List a different bunch of random process info from /proc/PID/status."),
 	   &info_proc_cmdlist);
 
   add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
-List a different bunch of random process info."),
+List current working directory of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
-List a different bunch of random process info."),
+List command line arguments of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
-List a different bunch of random process info."),
+List absolute filename for executable of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc *' help fix  [Re: [patch] `info proc ' completion]
  2011-11-03 14:12             ` [patch] `info proc *' help fix [Re: [patch] `info proc ' completion] Jan Kratochvil
@ 2011-11-03 16:57               ` Eli Zaretskii
  2011-11-03 17:07                 ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Eli Zaretskii @ 2011-11-03 16:57 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: pedro, gdb-patches, sergiodj

> Date: Thu, 3 Nov 2011 15:11:44 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: pedro@codesourcery.com, gdb-patches@sourceware.org, sergiodj@redhat.com
> 
> On Tue, 01 Nov 2011 17:22:42 +0100, Eli Zaretskii wrote:
> > I wonder if we could clean up this mess with 5 "different bunches of
> > info", while we are at that.
> 
> Sorry I somehow mishandled your mail, OK this way?

It's better.

>    add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
> -List a bunch of random process info."),
> +List annotated random process info from /proc/PID/stat."),
>  	   &info_proc_cmdlist);

I would suggest

 List process info from /proc/PID/stat.

> -List a different bunch of random process info."),
> +List a different bunch of random process info from /proc/PID/status."),

And likewise here.

> -List a different bunch of random process info."),
> +List current working directory of the process."),
>  	   &info_proc_cmdlist);
>  
>    add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
> -List a different bunch of random process info."),
> +List command line arguments of the process."),
>  	   &info_proc_cmdlist);
>  
>    add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
> -List a different bunch of random process info."),
> +List absolute filename for executable of the process."),
>  	   &info_proc_cmdlist);

These are OK.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc *' help fix  [Re: [patch] `info proc ' completion]
  2011-11-03 16:57               ` Eli Zaretskii
@ 2011-11-03 17:07                 ` Jan Kratochvil
  2011-11-03 18:08                   ` Eli Zaretskii
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-03 17:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pedro, gdb-patches, sergiodj

On Thu, 03 Nov 2011 17:56:48 +0100, Eli Zaretskii wrote:
> >    add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
> > -List a bunch of random process info."),
> > +List annotated random process info from /proc/PID/stat."),
> >  	   &info_proc_cmdlist);
> 
> I would suggest
> 
>  List process info from /proc/PID/stat.
> 
> > -List a different bunch of random process info."),
> > +List a different bunch of random process info from /proc/PID/status."),
> 
> And likewise here.

The problem is each `info proc XXX' commands reads it in /proc/PID/XXX file,
which may be obvious.  But I understand "stat" and "status" may be an
exception as it is difficult to describe what /proc/PID/{stat,status} contain.

I assume you meant it this way but asking again.


Thanks,
Jan


gdb/
2011-11-03  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Eli Zaretskii  <eliz@gnu.org>

	* linux-nat.c (_initialize_linux_nat): Improve help
	for `info proc stat', `info proc status', `info proc cwd',
	`info proc cmdline' and `info proc exe'.

--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -5887,23 +5887,23 @@ List of mapped memory regions."),
 	   &info_proc_cmdlist);
 
   add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
-List a bunch of random process info."),
+List process info from /proc/PID/stat."),
 	   &info_proc_cmdlist);
 
   add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
-List a different bunch of random process info."),
+List process info from /proc/PID/status."),
 	   &info_proc_cmdlist);
 
   add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
-List a different bunch of random process info."),
+List current working directory of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
-List a different bunch of random process info."),
+List command line arguments of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
-List a different bunch of random process info."),
+List absolute filename for executable of the process."),
 	   &info_proc_cmdlist);
 
   add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc *' help fix  [Re: [patch] `info proc ' completion]
  2011-11-03 17:07                 ` Jan Kratochvil
@ 2011-11-03 18:08                   ` Eli Zaretskii
  2011-11-03 18:25                     ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Eli Zaretskii @ 2011-11-03 18:08 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: pedro, gdb-patches, sergiodj

> Date: Thu, 3 Nov 2011 18:06:24 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: pedro@codesourcery.com, gdb-patches@sourceware.org, sergiodj@redhat.com
> 
> On Thu, 03 Nov 2011 17:56:48 +0100, Eli Zaretskii wrote:
> > >    add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
> > > -List a bunch of random process info."),
> > > +List annotated random process info from /proc/PID/stat."),
> > >  	   &info_proc_cmdlist);
> > 
> > I would suggest
> > 
> >  List process info from /proc/PID/stat.
> > 
> > > -List a different bunch of random process info."),
> > > +List a different bunch of random process info from /proc/PID/status."),
> > 
> > And likewise here.
> 
> The problem is each `info proc XXX' commands reads it in /proc/PID/XXX file,
> which may be obvious.  But I understand "stat" and "status" may be an
> exception as it is difficult to describe what /proc/PID/{stat,status} contain.
> 
> I assume you meant it this way but asking again.

Yes.  I wanted to get rid of the "random" part which makes an
impression that we display things that are not necessarily important.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [patch] `info proc *' help fix  [Re: [patch] `info proc ' completion]
  2011-11-03 18:08                   ` Eli Zaretskii
@ 2011-11-03 18:25                     ` Jan Kratochvil
  0 siblings, 0 replies; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-03 18:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pedro, gdb-patches, sergiodj

On Thu, 03 Nov 2011 19:08:34 +0100, Eli Zaretskii wrote:
> Yes.  I wanted to get rid of the "random" part which makes an
> impression that we display things that are not necessarily important.

Therefore checked it in:
	http://sourceware.org/ml/gdb-cvs/2011-11/msg00021.html


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-10-31  8:13     ` Jan Kratochvil
  2011-10-31 12:57       ` Pedro Alves
@ 2011-11-03 20:01       ` Sergio Durigan Junior
  2011-11-04 10:38         ` Eli Zaretskii
  2011-11-04 16:27         ` Jan Kratochvil
  1 sibling, 2 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-11-03 20:01 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Hello guys,

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> On Mon, 31 Oct 2011 04:16:51 +0100, Sergio Durigan Junior wrote:
>> > I think this function should not be based on sections at all, it should just
>> > read the segments.  Linux kernel does not dump any sections.  bfd creates some
>> > some sections from those segments (_bfd_elf_make_section_from_phdr) but they
>> > cannot / do not contain any additional info, those are there IMO only for
>> > better compatibility with sections-only consuming code.
>> 
>> Just to be clear, you're saying that I should actually forget about the
>> part of the code which checks inside (possible non-empty) sections in
>> the corefile, and just check immediately for segments?
>
> Yes.  Otherwise you need the tricks combining it with segments you do below
> anyway, moreover you can read in sections in core file generated by gcore
> which are completely useless,

Ok, I have addressed all the comments in this message, plus the comments
that Eli has made about the documentation bits.

Now this patch implements three commands:  `info core exe', `info core
mappings' and `info core all'.  When the corefile is ELF-compatible, and
there is support for ELF compiled (HAVE_ELF), I use it to figure out
information about segments (as proposed by Jan).  In this case, I do not
touch sections because they are useless.

When the corefile is not ELF-compatible, I use the old approach:
iterate over corefile sections and try to gather as much information as
I can about the memory mappings.  Unfortunately, I don't have a system
to test this non-ELF implementation, so I'm kindly ask for someone with
a Mac or Window to give it a try and see if it works.

I also implemented the `exe' command by simply extracting the executable
filename from the corefile BFD.  I also updated the documentation to
reflect this new command, along with the `all' command.

This has been regtested on TestFarm, without regressions for
x86{,_64,_64 w/ -m32}.

How does this patch look to you?

Thanks,

Sergio.

gdb/ChangeLog

2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* NEWS: Mention new `info core' command, along with its new
	subcommands `mappings', `exe' and `all'.
	* corefile.c: Include a bunch of header files needed to implement
	the `info core mappings'.
	(info_core_what): New enum.
	(info_core_print_core_exe): New function.
	(info_core_print_proc_map_non_elf): Likewise.
	(info_core_print_core_map_elf): Likewise.
	(info_core_print_core_map): Likewise.
	(info_core_cmd_1): Likewise.
	(info_core_cmd): Likewise.
	(info_core_cmd_mappings): Likewise.
	(info_core_cmd_exe): Likewise.
	(info_core_cmd_all): Likewise.
	(_initialize_core): Add new `info core' command, along with its new
	subcommands `mappings', `exe' and `all'.


gdb/doc/ChangeLog

2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.texinfo: Add documentation for `info core', and to its new
	subcommands `mappings', `exe' and `all'.


gdb/testsuite/ChangeLog

2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.base/corefile.exp: Add test for `info core', and for its new
	subcommands `mappings', `exe' and `all'.


diff --git a/gdb/NEWS b/gdb/NEWS
index 1713049..df9e573 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,20 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB has a new `info core' command, which can be used to display information
+  from a corefile.  Its subcommands are:
+
+  ** `info core mappings':  display information about memory mappings
+  from the corefile.
+
+  ** `info core exe':  display the executable filename that generated
+  the corefile.
+
+  ** `info core all':  display all of the above.
+
+It displays the memory
+  regions in a corefile, similar to `info proc mappings' command.
+
 * GDB now allows you to skip uninteresting functions and files when
   stepping with the "skip function" and "skip file" commands.
 
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..d0897fe 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include "inferior.h"
 #include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
 #include "target.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
 #include "gdb_stat.h"
 #include "completer.h"
 #include "exceptions.h"
+#include "objfiles.h"
 
 /* Local function declarations.  */
 
@@ -83,6 +89,280 @@ core_file_command (char *filename, int from_tty)
 }
 \f
 
+/* Implement the `info core' command.  */
+
+enum info_core_what
+  {
+    /* Display the default exe output.  */
+    IC_MINIMAL,
+
+    /* Display `info core mappings'.  */
+    IC_MAPPINGS,
+
+    /* Display `info core exe'.  */
+    IC_EXE,
+
+    /* Display all of the above.  */
+    IC_ALL
+  };
+
+/* Implement `info core exe' command.  */
+
+static void
+info_core_print_core_exe (void)
+{
+  const char *exe;
+
+  /* Getting the executable name.  */
+  exe = bfd_core_file_failing_command (core_bfd);
+
+  if (exe)
+    printf_filtered (_("exe = '%s'\n"), exe);
+  else
+    warning (_("Could not obtain executable name:  %s"),
+	     bfd_errmsg (bfd_get_error ()));
+}
+
+/* Helper function for `info_core_print_proc_map', used for non-ELF objects.
+
+   It is used to iterate over the corefile's BFD sections and print proper
+   information about memory-mappings.
+
+   BFD is the bfd used to get the sections.
+   SECT is the current section being "visited".
+   OBJ is not used.  */
+
+static void
+info_core_print_proc_map_non_elf (bfd *abfd, asection *sect, void *obj)
+{
+  /* We're interested in matching sections' names beginning with
+     `load', because they are the sections containing information
+     about the process' memory regions.  */
+  static const char *proc_map_match = "load";
+  int proc_map_match_size = strlen (proc_map_match);
+  /* The section's size.  */
+  bfd_size_type size;
+  /* We have to know the bitness of this architecture.  */
+  int bitness;
+  /* We'll use these later.  They are basically used for iterating
+     over every objfile in the system so that we can find needed
+     information about the memory region being examinated.  */
+  struct obj_section *s = NULL;
+  struct objfile *objfile = NULL;
+  /* Fields to be printed for the proc map.  */
+  bfd_vma start;
+  bfd_vma end = 0;
+  char *filename = NULL;
+
+  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+    /* This section is not useful.  */
+    return;
+
+  /* Bitness is important for formatting the text to output.  */
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (abfd));
+
+  /* Retrieving the section size.  */
+  size = bfd_section_size (bfd, sect);
+
+  start = sect->vma;
+  if (size)
+    end = sect->vma + size;
+
+  /* Now begins a new part of the work.  We still don't have complete
+     information about the memory region.  For example, we still need
+     to know the filename which is represented by the region.  Such
+     info can be gathered from the objfile's data structure, and for
+     that we must iterate over all the objsections and check if the
+     objsection's initial address is inside the section we have at hand.
+     If it is, then we can use this specific objsection to obtain the
+     missing data.  */
+  ALL_OBJSECTIONS (objfile, s)
+    if (!section_is_overlay (s) && obj_section_addr (s) >= start
+	&& obj_section_addr (s) <= end)
+      {
+	filename = s->objfile->name;
+	break;
+      }
+
+  if (bitness == 32)
+    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+  else
+    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
+		     start,
+		     end,
+		     (int) size,
+		     filename ? filename : "");
+}
+
+/* Helper function for `info_core_print_core_map' which handles objects
+   in the ELF format.  */
+
+static void
+info_core_print_core_map_elf (void)
+{
+#ifdef HAVE_ELF
+  int bitness;
+  int i;
+  unsigned int n_segs;
+  Elf_Internal_Phdr *p;
+
+  /* Bitness is important when formatting the text to be printed.  */
+  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
+
+  p = elf_tdata (core_bfd)->phdr;
+  if (!p)
+    error (_("Could not obtain mapped addresses."));
+
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+  else
+    printf_filtered ("  %18s %18s %10s %7s\n",
+		     "Start Addr",
+		     "  End Addr",
+		     "      Size", "objfile");
+
+  n_segs = elf_elfheader (core_bfd)->e_phnum;
+
+  for (i = 0; i < n_segs; i++, p++)
+    {
+      /* These are basically used for iterating over every objfile in
+	 the system so that we can find needed information about the
+	 memory region being examinated.  */
+      struct obj_section *s = NULL;
+      struct objfile *objfile = NULL;
+      /* Information about the segment.  */
+      bfd_vma start;
+      bfd_vma end;
+      bfd_vma size;
+      /* File associated with this memory region.  */
+      char *filename = NULL;
+
+      if (p->p_type != PT_LOAD)
+	/* We are only interested in PT_LOAD segments.  */
+	continue;
+
+      start = p->p_vaddr;
+      size = p->p_memsz;
+      end = start + size;
+
+      ALL_OBJSECTIONS (objfile, s)
+	if (!section_is_overlay (s) && obj_section_addr (s) >= start
+	    && obj_section_addr (s) <= end)
+	  {
+	    filename = s->objfile->name;
+	    break;
+	  }
+
+      if (bitness == 32)
+	printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
+			 start,
+			 end,
+			 (int) size,
+			 filename ? filename : "");
+      else
+	printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
+			 start,
+			 end,
+			 (int) size,
+			 filename ? filename : "");
+    }
+#else
+  error (_("Your system does not support ELF format."));
+#endif /* HAVE_ELF */
+}
+
+/* Implement the `info core map' command.  */
+
+static void
+info_core_print_core_map (void)
+{
+  gdb_assert (core_bfd != NULL);
+
+  if (bfd_get_flavour (core_bfd) == bfd_target_elf_flavour)
+    info_core_print_core_map_elf ();
+  else
+    bfd_map_over_sections (core_bfd,
+			   info_core_print_proc_map_non_elf,
+			   NULL);
+}
+
+/* Implement the `info core' command.  */
+
+static void
+info_core_cmd_1 (char *args, enum info_core_what what, int from_tty)
+{
+  char **argv = NULL;
+  int mappings_f = (what == IC_MAPPINGS || what == IC_ALL);
+  int exe_f = (what == IC_MINIMAL || what == IC_EXE || what == IC_ALL);
+  struct cleanup *c = NULL;
+
+  if (!core_bfd)
+    error (_("You are not using a corefile at the moment."));
+
+  if (args)
+    {
+      /* Break up 'args' into an argv array.  */
+      argv = gdb_buildargv (args);
+      c = make_cleanup_freeargv (argv);
+    }
+  while (argv != NULL && *argv != NULL)
+    {
+      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+	{
+	  mappings_f = 1;
+	}
+      argv++;
+    }
+
+  if (exe_f)
+    info_core_print_core_exe ();
+
+  if (mappings_f)
+    info_core_print_core_map ();
+
+  if (c)
+    do_cleanups (c);
+}
+
+/* Implement `info core' without parameters.  */
+static void
+info_core_cmd (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_MINIMAL, from_tty);
+}
+
+/* Implement `info core mappings'.  */
+
+static void
+info_core_cmd_mappings (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_MAPPINGS, from_tty);
+}
+
+/* Implement `info core exe'.  */
+
+static void
+info_core_cmd_exe (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_EXE, from_tty);
+}
+
+/* Implement `info core all'.  */
+
+static void
+info_core_cmd_all (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_ALL, from_tty);
+}
+
 /* If there are two or more functions that wish to hook into
    exec_file_command, this function will call all of the hook
    functions.  */
@@ -449,6 +729,26 @@ void
 _initialize_core (void)
 {
   struct cmd_list_element *c;
+  static struct cmd_list_element *info_core_cmdlist;
+
+  add_prefix_cmd ("core", class_info, info_core_cmd,
+		  _("\
+Show information about a corefile.\n\
+The command uses the corefile loaded."),
+		  &info_core_cmdlist, "info core ",
+		  1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, info_core_cmd_mappings, _("\
+List of mapped memory regions."),
+	   &info_core_cmdlist);
+
+  add_cmd ("exe", class_info, info_core_cmd_exe, _("\
+List absolute filename for executable which generated the corefile."),
+	   &info_core_cmdlist);
+
+  add_cmd ("all", class_info, info_core_cmd_all, _("\
+List all available corefile information."),
+	   &info_core_cmdlist);
 
   c = add_cmd ("core-file", class_files, core_file_command, _("\
 Use FILE as core dump for examining memory and registers.\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 93450c6..e138f5a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17829,6 +17829,62 @@ processes and all the threads within each process.
 For QNX Neutrino only, this command displays the list of all mapinfos.
 @end table
 
+@node Process Information from Core Dump File
+@subsection Process Information from Core Dump File
+@cindex examine core dump file process information
+@cindex process info via core dump file
+
+If your system supports the generation of core dump files (core files), you
+can use them to obtain information about processes.  For that, you can use
+the command @code{info core} inside @value{GDBN} to report information like
+the memory mappings of the process when the core dump was generated.
+@code{info core} works only on systems that support core dump files, and only
+when you are using a core dump file inside @value{GDBN}.
+
+@xref{Core File Generation}, for information on how to generate core dump
+files inside @value{GDBN}.  @xref{Files}, for information on invoking
+@value{GDBN} in the post-mortem debugging mode.
+
+@table @code
+@kindex info core
+@cindex core dump file, process information
+@item info core
+@itemx info core mappings
+@cindex memory address space mappings inside a core dump file
+Report the memory address ranges accessible in the core dump file.  Assuming
+you have a core dump file and it is loaded into @value{GDBN}, the output of
+the command will be similar to:
+
+@smallexample
+(@value{GDBP}) info core mappings
+Mapped address spaces:
+
+  Start Addr      End Addr      Size objfile
+    0x400000      0x401000    0x1000 /tmp/a.out
+    0x600000      0x601000    0x1000 /tmp/a.out
+0x397de00000  0x397de1f000   0x1f000 /usr/lib/debug/lib/ld.so.debug
+0x397e01e000  0x397e01f000    0x1000 /usr/lib/debug/lib/ld.so.debug
+0x397e01f000  0x397e020000    0x1000 /usr/lib/debug/lib/ld.so.debug
+0x397e020000  0x397e021000    0x1000 /usr/lib/debug/lib/ld.so.debug
+0x397e200000  0x397e391000  0x191000 /usr/lib/debug/lib/libc.so.debug
+0x397e591000  0x397e595000    0x4000 /usr/lib/debug/lib/libc.so.debug
+0x397e595000  0x397e596000    0x1000 /usr/lib/debug/lib/libc.so.debug
+0x397e596000  0x397e59c000    0x6000
+@end smallexample
+
+@item info core exe
+Show the filename of the process that generated this core dump file.
+
+@smallexample
+(@value{GDBP}) info core exe
+exe = '/tmp/a.out'
+@end smallexample
+
+@item info core all
+Show all the information about the core dump file described under all of
+the above @code{info core} subcommands.
+@end table
+
 @node DJGPP Native
 @subsection Features for Debugging @sc{djgpp} Programs
 @cindex @sc{djgpp} debugging
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..ccf226f 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,18 @@ gdb_test_multiple "x/8bd buf2" "$test" {
     }
 }
 
+# Test the `info core mappings' command.
+set ws "\[ \t\]+"
+set test "test info core mappings"
+gdb_test "info core mappings" \
+	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+	$test
+
+# Test the `info core exe' command.
+set test "test info core exe"
+gdb_test "info core exe" \
+	"exe = .*"
+
 # test reinit_frame_cache
 
 gdb_load ${binfile}

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-03 20:01       ` [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
@ 2011-11-04 10:38         ` Eli Zaretskii
  2011-11-04 16:27         ` Jan Kratochvil
  1 sibling, 0 replies; 83+ messages in thread
From: Eli Zaretskii @ 2011-11-04 10:38 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: jan.kratochvil, gdb-patches

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 03 Nov 2011 18:00:39 -0200
> 
> +It displays the memory
> +  regions in a corefile, similar to `info proc mappings' command.

Bad formatting.

Otherwise, fine with me.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-03 20:01       ` [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
  2011-11-04 10:38         ` Eli Zaretskii
@ 2011-11-04 16:27         ` Jan Kratochvil
  2011-11-08  1:49           ` Sergio Durigan Junior
  1 sibling, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-04 16:27 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

Hi Sergio,

On Thu, 03 Nov 2011 21:00:39 +0100, Sergio Durigan Junior wrote:
> gdb/ChangeLog
> 
> 2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	Implement `info core mappings'.
> 	* NEWS: Mention new `info core' command, along with its new
> 	subcommands `mappings', `exe' and `all'.
> 	* corefile.c: Include a bunch of header files needed to implement
> 	the `info core mappings'.
> 	(info_core_what): New enum.
> 	(info_core_print_core_exe): New function.
> 	(info_core_print_proc_map_non_elf): Likewise.
> 	(info_core_print_core_map_elf): Likewise.
> 	(info_core_print_core_map): Likewise.
> 	(info_core_cmd_1): Likewise.
> 	(info_core_cmd): Likewise.
> 	(info_core_cmd_mappings): Likewise.
> 	(info_core_cmd_exe): Likewise.
> 	(info_core_cmd_all): Likewise.
> 	(_initialize_core): Add new `info core' command, along with its new
> 	subcommands `mappings', `exe' and `all'.
> 
> 
> gdb/doc/ChangeLog
> 
> 2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	Implement `info core mappings'.
> 	* gdb.texinfo: Add documentation for `info core', and to its new
> 	subcommands `mappings', `exe' and `all'.
> 
> 
> gdb/testsuite/ChangeLog
> 
> 2011-11-03  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	Implement `info core mappings'.
> 	* gdb.base/corefile.exp: Add test for `info core', and for its new
> 	subcommands `mappings', `exe' and `all'.
> 
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 1713049..df9e573 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,20 @@
>  
>  *** Changes since GDB 7.3.1
>  
> +* GDB has a new `info core' command, which can be used to display information
> +  from a corefile.  Its subcommands are:
> +
> +  ** `info core mappings':  display information about memory mappings
> +  from the corefile.
> +
> +  ** `info core exe':  display the executable filename that generated
> +  the corefile.
> +
> +  ** `info core all':  display all of the above.

It has been approved by Eli but FYI I would do: s/:  /: /


> +
> +It displays the memory
> +  regions in a corefile, similar to `info proc mappings' command.
> +
>  * GDB now allows you to skip uninteresting functions and files when
>    stepping with the "skip function" and "skip file" commands.
>  
> diff --git a/gdb/corefile.c b/gdb/corefile.c
> index ce3b755..d0897fe 100644
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
> @@ -24,17 +24,23 @@
>  #include <errno.h>
>  #include <signal.h>
>  #include <fcntl.h>
> +#include <ctype.h>
>  #include "inferior.h"
>  #include "symtab.h"
> +#include "gdbarch.h"
> +#include "arch-utils.h"
>  #include "command.h"
>  #include "gdbcmd.h"
>  #include "bfd.h"
> +#include "elf-bfd.h"
> +#include "elf/internal.h"
>  #include "target.h"
>  #include "gdbcore.h"
>  #include "dis-asm.h"
>  #include "gdb_stat.h"
>  #include "completer.h"
>  #include "exceptions.h"
> +#include "objfiles.h"
>  
>  /* Local function declarations.  */
>  
> @@ -83,6 +89,280 @@ core_file_command (char *filename, int from_tty)
>  }
>  \f
>  
> +/* Implement the `info core' command.  */
> +
> +enum info_core_what
> +  {
> +    /* Display the default exe output.  */
> +    IC_MINIMAL,
> +
> +    /* Display `info core mappings'.  */
> +    IC_MAPPINGS,
> +
> +    /* Display `info core exe'.  */
> +    IC_EXE,
> +
> +    /* Display all of the above.  */
> +    IC_ALL
> +  };
> +
> +/* Implement `info core exe' command.  */
> +
> +static void
> +info_core_print_core_exe (void)
> +{
> +  const char *exe;
> +
> +  /* Getting the executable name.  */
> +  exe = bfd_core_file_failing_command (core_bfd);
> +
> +  if (exe)
> +    printf_filtered (_("exe = '%s'\n"), exe);
> +  else
> +    warning (_("Could not obtain executable name:  %s"),

Again IMO s/:  /: /, two spaces are not used in GDB.


> +	     bfd_errmsg (bfd_get_error ()));
> +}
> +
> +/* Helper function for `info_core_print_proc_map', used for non-ELF objects.
> +
> +   It is used to iterate over the corefile's BFD sections and print proper
> +   information about memory-mappings.
> +
> +   BFD is the bfd used to get the sections.
      ABFD

> +   SECT is the current section being "visited".
> +   OBJ is not used.  */
> +
> +static void
> +info_core_print_proc_map_non_elf (bfd *abfd, asection *sect, void *obj)
> +{
> +  /* We're interested in matching sections' names beginning with
> +     `load', because they are the sections containing information
> +     about the process' memory regions.  */
> +  static const char *proc_map_match = "load";

static const char proc_map_match[] = "load";

to save one read/write pointer. :-)


> +  int proc_map_match_size = strlen (proc_map_match);
> +  /* The section's size.  */
> +  bfd_size_type size;
> +  /* We have to know the bitness of this architecture.  */
> +  int bitness;
> +  /* We'll use these later.  They are basically used for iterating
> +     over every objfile in the system so that we can find needed
> +     information about the memory region being examinated.  */
> +  struct obj_section *s = NULL;
> +  struct objfile *objfile = NULL;

Redundant two initializations.


> +  /* Fields to be printed for the proc map.  */
> +  bfd_vma start;
> +  bfd_vma end = 0;
> +  char *filename = NULL;
> +
> +  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
> +    /* This section is not useful.  */
> +    return;
> +
> +  /* Bitness is important for formatting the text to output.  */
> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (abfd));
> +
> +  /* Retrieving the section size.  */
> +  size = bfd_section_size (bfd, sect);
> +
> +  start = sect->vma;
> +  if (size)
> +    end = sect->vma + size;

I think for zero-sized segments END should be equal START.


> +
> +  /* Now begins a new part of the work.  We still don't have complete
> +     information about the memory region.  For example, we still need
> +     to know the filename which is represented by the region.  Such
> +     info can be gathered from the objfile's data structure, and for
> +     that we must iterate over all the objsections and check if the
> +     objsection's initial address is inside the section we have at hand.
> +     If it is, then we can use this specific objsection to obtain the
> +     missing data.  */
> +  ALL_OBJSECTIONS (objfile, s)
> +    if (!section_is_overlay (s) && obj_section_addr (s) >= start
> +	&& obj_section_addr (s) <= end)

Separate debug info check like for ELF.

The full coverage as suggested for ELF is not possible foe non-ELF so I do not
know what to do better than what you do.


> +      {
> +	filename = s->objfile->name;
> +	break;
> +      }
> +
> +  if (bitness == 32)
> +    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",

Why %7s and not %s?  The filename is almost always longer than 7 anyway.


> +		     start,
> +		     end,
> +		     (int) size,
> +		     filename ? filename : "");
> +  else
> +    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
> +		     start,
> +		     end,
> +		     (int) size,
> +		     filename ? filename : "");

You cannot (a) assume bfd_vma is compatible with %lx, for example on i386 with
--enable-64-bit-bfd such GDB will fail to properly display i386 core files
from kdump on >=4GB machine which uses ELF64, `long' is there 32-bit.

There is BFD_VMA_FMT.

Still requesting to rather use CORE_ADDR and paddress everywhere as this is
GDB and not BFD.


> +}
> +
> +/* Helper function for `info_core_print_core_map' which handles objects
> +   in the ELF format.  */
> +
> +static void
> +info_core_print_core_map_elf (void)
> +{
> +#ifdef HAVE_ELF

One could also move it to elfread.c via a function pointer similar to
gnu_ifunc_fns_p but I am OK with this #ifdef.


> +  int bitness;
> +  int i;
> +  unsigned int n_segs;
> +  Elf_Internal_Phdr *p;
> +
> +  /* Bitness is important when formatting the text to be printed.  */
> +  bitness = gdbarch_addr_bit (gdbarch_from_bfd (core_bfd));
> +
> +  p = elf_tdata (core_bfd)->phdr;
> +  if (!p)
> +    error (_("Could not obtain mapped addresses."));
> +
> +  printf_filtered (_("Mapped address spaces:\n\n"));
> +  if (bitness == 32)
> +    printf_filtered ("\t%10s %10s %10s %7s\n",
> +		     "Start Addr",
> +		     "  End Addr",

s/Addr/Address/, there is enough space.


> +		     "      Size", "objfile");
> +  else
> +    printf_filtered ("  %18s %18s %10s %7s\n",
> +		     "Start Addr",
> +		     "  End Addr",
> +		     "      Size", "objfile");
> +
> +  n_segs = elf_elfheader (core_bfd)->e_phnum;
> +
> +  for (i = 0; i < n_segs; i++, p++)

Variable `i' is not used in this function.


> +    {
> +      /* These are basically used for iterating over every objfile in
> +	 the system so that we can find needed information about the
> +	 memory region being examinated.  */
> +      struct obj_section *s = NULL;
> +      struct objfile *objfile = NULL;

These two NULL initializations are redundant.


There should be empty lines before comments, even for variable declarations,
in the whole file everywhere.

> +      /* Information about the segment.  */
> +      bfd_vma start;
> +      bfd_vma end;
> +      bfd_vma size;
> +      /* File associated with this memory region.  */
> +      char *filename = NULL;

I would initialize it by "", was your NULL intentional?  (again for non-ELF)


> +
> +      if (p->p_type != PT_LOAD)
> +	/* We are only interested in PT_LOAD segments.  */
> +	continue;
> +
> +      start = p->p_vaddr;
> +      size = p->p_memsz;
> +      end = start + size;
> +
> +      ALL_OBJSECTIONS (objfile, s)
> +	if (!section_is_overlay (s) && obj_section_addr (s) >= start
> +	    && obj_section_addr (s) <= end)

Also I think you should discard the separate debug info objfiles.  I find
wrong to display:
        0x37aa200000       0x37aa222000    0x22000 /usr/lib/debug/lib64/ld-2.14.90.so.debug
when it in fact means:
        0x37aa200000       0x37aa222000    0x22000 /lib64/ld-2.14.90.so

Be aware even for core file loading /usr/lib/debug/lib64/ld-2.14.90.so.debug
is not enough as some parts (such as .symtab) as sometimes contained just in
/lib64/ld-2.14.90.so, also readonly sections such as .text are contained only
in /lib64/ld-2.14.90.so and not present in the core file so printing just the
.debug file is wrong.


> +	  {
> +	    filename = s->objfile->name;
> +	    break;
> +	  }

I think the logic should be opposite.  Not to find any part of the core
segment from some file but ensure the whole segment is mapped from that file.

For ELF core files you should rather check also the ELF segments in
objfiles->obfd and verify it is fully covered.  (I said off-list something
different, not seeing the code, sorry.)  That is verify every byte between
0x37aa200000 and 0x37aa222000 belongs to any of the segments from such file.
Otherwise you may print a filename for some core file segment while only part
of that segment is from that file (it probably will not happen for normal core
files but GDB is for debugging problems so it should never give inexact
results).


> +
> +      if (bitness == 32)
> +	printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
> +			 start,
> +			 end,
> +			 (int) size,
> +			 filename ? filename : "");

Could you print all the info readelf -Wa prints?  I would use rather readelf
to see the protection bits, also I guess the file size vs. mem size may
suggest if it is a data segment or code segment, up to you how to display it,
even some indicator "from core file" (memsize==filesize) vs. "from local file"
(filesize==0) vs. "partial" (others, e.g. filesize==0x1000) could be enough.


> +      else
> +	printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
> +			 start,
> +			 end,
> +			 (int) size,
> +			 filename ? filename : "");
> +    }
> +#else
> +  error (_("Your system does not support ELF format."));
> +#endif /* HAVE_ELF */
> +}
> +
> +/* Implement the `info core map' command.  */
> +
> +static void
> +info_core_print_core_map (void)
> +{
> +  gdb_assert (core_bfd != NULL);
> +
> +  if (bfd_get_flavour (core_bfd) == bfd_target_elf_flavour)
> +    info_core_print_core_map_elf ();
> +  else
> +    bfd_map_over_sections (core_bfd,
> +			   info_core_print_proc_map_non_elf,
> +			   NULL);
> +}
> +
> +/* Implement the `info core' command.  */
> +
> +static void
> +info_core_cmd_1 (char *args, enum info_core_what what, int from_tty)
> +{
> +  char **argv = NULL;
> +  int mappings_f = (what == IC_MAPPINGS || what == IC_ALL);
> +  int exe_f = (what == IC_MINIMAL || what == IC_EXE || what == IC_ALL);
> +  struct cleanup *c = NULL;
> +
> +  if (!core_bfd)
> +    error (_("You are not using a corefile at the moment."));
> +


> +  if (args)
> +    {
> +      /* Break up 'args' into an argv array.  */
> +      argv = gdb_buildargv (args);
> +      c = make_cleanup_freeargv (argv);
> +    }
> +  while (argv != NULL && *argv != NULL)
> +    {
> +      if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
> +	{
> +	  mappings_f = 1;
> +	}
> +      argv++;
> +    }

This is completely redundant block, this function should just complain if ARGS
contains anything as the "exec"/"mappings" parameters are already parsed
through info_core_cmd_mappings/info_core_cmd_exe.


> +
> +  if (exe_f)
> +    info_core_print_core_exe ();
> +
> +  if (mappings_f)
> +    info_core_print_core_map ();
> +
> +  if (c)
> +    do_cleanups (c);

If ARGS was NULL "c" is left NULL, which will execute all the cleanups stored
even before and unrelated to info_core_cmd_1.  You must either if (args && c)
or pre-initialize C by make_cleanup (null_cleanup, NULL) or else-initialize
C the same way.

In fact I see now whole C is redundant together with that parsing block.


> +}
> +
> +/* Implement `info core' without parameters.  */

Empty line.


> +static void
> +info_core_cmd (char *args, int from_tty)
> +{
> +  info_core_cmd_1 (args, IC_MINIMAL, from_tty);
> +}
> +
> +/* Implement `info core mappings'.  */
> +
> +static void
> +info_core_cmd_mappings (char *args, int from_tty)
> +{
> +  info_core_cmd_1 (args, IC_MAPPINGS, from_tty);
> +}
> +
> +/* Implement `info core exe'.  */
> +
> +static void
> +info_core_cmd_exe (char *args, int from_tty)
> +{
> +  info_core_cmd_1 (args, IC_EXE, from_tty);
> +}
> +
> +/* Implement `info core all'.  */
> +
> +static void
> +info_core_cmd_all (char *args, int from_tty)
> +{
> +  info_core_cmd_1 (args, IC_ALL, from_tty);
> +}
> +
>  /* If there are two or more functions that wish to hook into
>     exec_file_command, this function will call all of the hook
>     functions.  */
> @@ -449,6 +729,26 @@ void
>  _initialize_core (void)
>  {
>    struct cmd_list_element *c;
> +  static struct cmd_list_element *info_core_cmdlist;
> +
> +  add_prefix_cmd ("core", class_info, info_core_cmd,
> +		  _("\
> +Show information about a corefile.\n\
> +The command uses the corefile loaded."),
> +		  &info_core_cmdlist, "info core ",
> +		  1/*allow-unknown*/, &infolist);
> +
> +  add_cmd ("mappings", class_info, info_core_cmd_mappings, _("\
> +List of mapped memory regions."),
> +	   &info_core_cmdlist);
> +
> +  add_cmd ("exe", class_info, info_core_cmd_exe, _("\
> +List absolute filename for executable which generated the corefile."),
> +	   &info_core_cmdlist);
> +
> +  add_cmd ("all", class_info, info_core_cmd_all, _("\
> +List all available corefile information."),
> +	   &info_core_cmdlist);
>  
>    c = add_cmd ("core-file", class_files, core_file_command, _("\
>  Use FILE as core dump for examining memory and registers.\n\
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 93450c6..e138f5a 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -17829,6 +17829,62 @@ processes and all the threads within each process.
>  For QNX Neutrino only, this command displays the list of all mapinfos.
>  @end table
>  
> +@node Process Information from Core Dump File
> +@subsection Process Information from Core Dump File
> +@cindex examine core dump file process information
> +@cindex process info via core dump file
> +
> +If your system supports the generation of core dump files (core files), you
> +can use them to obtain information about processes.  For that, you can use
> +the command @code{info core} inside @value{GDBN} to report information like
> +the memory mappings of the process when the core dump was generated.
> +@code{info core} works only on systems that support core dump files, and only
> +when you are using a core dump file inside @value{GDBN}.
> +
> +@xref{Core File Generation}, for information on how to generate core dump
> +files inside @value{GDBN}.  @xref{Files}, for information on invoking
> +@value{GDBN} in the post-mortem debugging mode.
> +
> +@table @code
> +@kindex info core
> +@cindex core dump file, process information
> +@item info core
> +@itemx info core mappings
> +@cindex memory address space mappings inside a core dump file
> +Report the memory address ranges accessible in the core dump file.  Assuming
> +you have a core dump file and it is loaded into @value{GDBN}, the output of
> +the command will be similar to:
> +
> +@smallexample
> +(@value{GDBP}) info core mappings
> +Mapped address spaces:
> +
> +  Start Addr      End Addr      Size objfile
> +    0x400000      0x401000    0x1000 /tmp/a.out
> +    0x600000      0x601000    0x1000 /tmp/a.out
> +0x397de00000  0x397de1f000   0x1f000 /usr/lib/debug/lib/ld.so.debug
> +0x397e01e000  0x397e01f000    0x1000 /usr/lib/debug/lib/ld.so.debug
> +0x397e01f000  0x397e020000    0x1000 /usr/lib/debug/lib/ld.so.debug
> +0x397e020000  0x397e021000    0x1000 /usr/lib/debug/lib/ld.so.debug
> +0x397e200000  0x397e391000  0x191000 /usr/lib/debug/lib/libc.so.debug
> +0x397e591000  0x397e595000    0x4000 /usr/lib/debug/lib/libc.so.debug
> +0x397e595000  0x397e596000    0x1000 /usr/lib/debug/lib/libc.so.debug

Here remove the .debug suffixes as noted above.


> +0x397e596000  0x397e59c000    0x6000
> +@end smallexample
> +
> +@item info core exe
> +Show the filename of the process that generated this core dump file.
> +
> +@smallexample
> +(@value{GDBP}) info core exe
> +exe = '/tmp/a.out'
> +@end smallexample
> +
> +@item info core all
> +Show all the information about the core dump file described under all of
> +the above @code{info core} subcommands.
> +@end table
> +
>  @node DJGPP Native
>  @subsection Features for Debugging @sc{djgpp} Programs
>  @cindex @sc{djgpp} debugging
> diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
> index 5b0cdf1..ccf226f 100644
> --- a/gdb/testsuite/gdb.base/corefile.exp
> +++ b/gdb/testsuite/gdb.base/corefile.exp
> @@ -171,6 +171,18 @@ gdb_test_multiple "x/8bd buf2" "$test" {
>      }
>  }
>  
> +# Test the `info core mappings' command.
> +set ws "\[ \t\]+"
> +set test "test info core mappings"
> +gdb_test "info core mappings" \
> +	".*Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
         ^^ useless leading .*

> +	$test
> +
> +# Test the `info core exe' command.
> +set test "test info core exe"
> +gdb_test "info core exe" \
> +	"exe = .*"

Could you put some content there?  Testing for .* is not much useful.

> +
>  # test reinit_frame_cache
>  
>  gdb_load ${binfile}


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-04 16:27         ` Jan Kratochvil
@ 2011-11-08  1:49           ` Sergio Durigan Junior
  2011-11-08 21:47             ` Jan Kratochvil
  2011-11-09 20:32             ` Jan Kratochvil
  0 siblings, 2 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-11-08  1:49 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Hello,

Thanks for the review.  I am still working on the patch, but I have a question.

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> On Thu, 03 Nov 2011 21:00:39 +0100, Sergio Durigan Junior wrote:
>> +	  {
>> +	    filename = s->objfile->name;
>> +	    break;
>> +	  }
>
> I think the logic should be opposite.  Not to find any part of the core
> segment from some file but ensure the whole segment is mapped from that file.
>
> For ELF core files you should rather check also the ELF segments in
> objfiles->obfd and verify it is fully covered.  (I said off-list something
> different, not seeing the code, sorry.)  That is verify every byte between
> 0x37aa200000 and 0x37aa222000 belongs to any of the segments from such file.
> Otherwise you may print a filename for some core file segment while only part
> of that segment is from that file (it probably will not happen for normal core
> files but GDB is for debugging problems so it should never give inexact
> results).

This one is giving me headaches...  When I implemented the algorithm,
some objfiles were supressed.  Anyway, I'm still working on it (and
that's not the question I wanted to ask).

>> +
>> +      if (bitness == 32)
>> +	printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
>> +			 start,
>> +			 end,
>> +			 (int) size,
>> +			 filename ? filename : "");
>
> Could you print all the info readelf -Wa prints?  I would use rather readelf
> to see the protection bits, also I guess the file size vs. mem size may
> suggest if it is a data segment or code segment, up to you how to display it,
> even some indicator "from core file" (memsize==filesize) vs. "from local file"
> (filesize==0) vs. "partial" (others, e.g. filesize==0x1000) could be
> enough.

When you say "all the info", what do you mean?  I am not sure I
understood your sentence above.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-08  1:49           ` Sergio Durigan Junior
@ 2011-11-08 21:47             ` Jan Kratochvil
  2011-11-09 20:32             ` Jan Kratochvil
  1 sibling, 0 replies; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-08 21:47 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Tue, 08 Nov 2011 02:48:54 +0100, Sergio Durigan Junior wrote:
> >> +      if (bitness == 32)
> >> +	printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
> >> +			 start,
> >> +			 end,
> >> +			 (int) size,
> >> +			 filename ? filename : "");
> >
> > Could you print all the info readelf -Wa prints?  I would use rather readelf
> > to see the protection bits, also I guess the file size vs. mem size may
> > suggest if it is a data segment or code segment, up to you how to display it,
> > even some indicator "from core file" (memsize==filesize) vs. "from local file"
> > (filesize==0) vs. "partial" (others, e.g. filesize==0x1000) could be
> > enough.
> 
> When you say "all the info", what do you mean?  I am not sure I
> understood your sentence above.

Currently you display:
          Start Addr           End Addr       Size objfile
        0x37aa200000       0x37aa222000    0x22000 /lib64/ld-2.14.90.so
FYI max width:
  0xffffffffffffffff 0xffffffffffffffff

I see now the formatstring is a copy from `info proc mappings'.

The readelf -Wl output is:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0xa6c000 0x00007f9623a5b000 0x0000000000000000 0x001000 0x015000 R E 0x1000

Flg must be there.  It suggests whether that part is about segment with .text
or with .data etc.

Somehow both FileSiz MemSiz should be there.  I would find OK (this is RFC) to
put there just MemSiz together with single-character column:
	C if FileSiz == MemSiz
	I if FileSiz == pagesize (that is only the build-id header is present)
	F if FileSiz == 0
	? otherwise
But not sure if one gets used to this format.

It is questionable whether Offset should be there.  I use that value but
probably when one starts editing/searching etc. corefile one can run separate
readelf anyway and it would be just redundant in the GDB output.  So I do not
want Offset there.

32:
    printf_filtered ("\t%#10lx %#10lx %#10x %7s\n",
I think \t should be removed, screen width is scarce.
%7s should be %s.

64:
    printf_filtered ("  %#18lx %#18lx %#10x %7s\n",
I think "  " should be removed, screen width is scarce.
%7s should be %s.

Feel free to disagree, this is more about bikeshedding, just expressing my
opinions with reasons for discussion.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-08  1:49           ` Sergio Durigan Junior
  2011-11-08 21:47             ` Jan Kratochvil
@ 2011-11-09 20:32             ` Jan Kratochvil
  2011-11-16  4:10               ` Sergio Durigan Junior
  1 sibling, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-11-09 20:32 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Tue, 08 Nov 2011 02:48:54 +0100, Sergio Durigan Junior wrote:
> > On Thu, 03 Nov 2011 21:00:39 +0100, Sergio Durigan Junior wrote:
> > For ELF core files you should rather check also the ELF segments in
> > objfiles->obfd and verify it is fully covered.
[...]
> This one is giving me headaches...

I have discovered (a bit late) ABRT already supports dumping /proc/PID/maps
along the core file for a dying process (at least on Fedora 16), together with
many other useful information.  While I heard Solaris puts some such info
_into_ the core file I find OK to put it _along_ the core file - in the whole
crash report.

So I understand in some corner cases without ABRT `info core mappings' may be
useful but I no longer find too much interest in it myself and some
approximate file suggestion may be just good enough there.  After all the
whole information about where is which file mapped is just an approximate
suggestion by GDB anyway.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-09 20:32             ` Jan Kratochvil
@ 2011-11-16  4:10               ` Sergio Durigan Junior
  2011-11-21 16:15                 ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-11-16  4:10 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> On Tue, 08 Nov 2011 02:48:54 +0100, Sergio Durigan Junior wrote:
>> > On Thu, 03 Nov 2011 21:00:39 +0100, Sergio Durigan Junior wrote:
>> > For ELF core files you should rather check also the ELF segments in
>> > objfiles->obfd and verify it is fully covered.
> [...]
>> This one is giving me headaches...
>
> So I understand in some corner cases without ABRT `info core mappings' may be
> useful but I no longer find too much interest in it myself and some
> approximate file suggestion may be just good enough there.  After all the
> whole information about where is which file mapped is just an approximate
> suggestion by GDB anyway.

Ok, so I would like to ask for another round of review of this patch
then.  I am aware of Ulrich's work towards a new `info mappings'
command, but since I've got no response from him yet, I decided to
continue my efforts here.

The documentation bits were already approved by Eli, and the code was
discussed a lot with Jan.  This patch causes no regression, as mentioned
earlier.  For more details, please read the whole thread.

Thanks a lot.

2011-11-16  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* NEWS: Mention new `info core' command, along with its new
	subcommands `mappings', `exe' and `all'.
	* corefile.c: Include a bunch of header files needed to implement
	the `info core mappings'.
	(info_core_what): New enum.
	(info_core_print_core_exe): New function.
	(info_core_print_proc_map_non_elf): Likewise.
	(info_core_print_core_map_elf): Likewise.
	(info_core_print_core_map): Likewise.
	(info_core_cmd_1): Likewise.
	(info_core_cmd): Likewise.
	(info_core_cmd_mappings): Likewise.
	(info_core_cmd_exe): Likewise.
	(info_core_cmd_all): Likewise.
	(_initialize_core): Add new `info core' command, along with its new
	subcommands `mappings', `exe' and `all'.

2011-11-16  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.texinfo: Add documentation for `info core', and to its new
	subcommands `mappings', `exe' and `all'.

2011-11-16  Sergio Durigan Junior  <sergiodj@redhat.com>

	Implement `info core mappings'.
	* gdb.base/corefile.exp: Add test for `info core', and for its new
	subcommands `mappings', `exe' and `all'.

diff --git a/gdb/NEWS b/gdb/NEWS
index c4e59c4..e649727 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,17 @@
 
 *** Changes since GDB 7.3.1
 
+* GDB has a new `info core' command, which can be used to display information
+  from a corefile.  Its subcommands are:
+
+  ** `info core mappings': display information about memory mappings
+  from the corefile.
+
+  ** `info core exe': display the executable filename that generated
+  the corefile.
+
+  ** `info core all': display all of the above.
+
 * GDB now allows you to skip uninteresting functions and files when
   stepping with the "skip function" and "skip file" commands.
 
diff --git a/gdb/corefile.c b/gdb/corefile.c
index ce3b755..9302476 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -24,17 +24,23 @@
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include "inferior.h"
 #include "symtab.h"
+#include "gdbarch.h"
+#include "arch-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "bfd.h"
+#include "elf-bfd.h"
+#include "elf/internal.h"
 #include "target.h"
 #include "gdbcore.h"
 #include "dis-asm.h"
 #include "gdb_stat.h"
 #include "completer.h"
 #include "exceptions.h"
+#include "objfiles.h"
 
 /* Local function declarations.  */
 
@@ -83,6 +89,267 @@ core_file_command (char *filename, int from_tty)
 }
 \f
 
+/* Implement the `info core' command.  */
+
+enum info_core_what
+  {
+    /* Display the default exe output.  */
+    IC_MINIMAL,
+
+    /* Display `info core mappings'.  */
+    IC_MAPPINGS,
+
+    /* Display `info core exe'.  */
+    IC_EXE,
+
+    /* Display all of the above.  */
+    IC_ALL
+  };
+
+/* Implement `info core exe' command.  */
+
+static void
+info_core_print_core_exe (void)
+{
+  const char *exe;
+
+  /* Getting the executable name.  */
+  exe = bfd_core_file_failing_command (core_bfd);
+
+  if (exe)
+    printf_filtered (_("exe = '%s'\n"), exe);
+  else
+    warning (_("Could not obtain executable name: %s"),
+	     bfd_errmsg (bfd_get_error ()));
+}
+
+/* Helper function for `info_core_print_proc_map', used for non-ELF objects.
+
+   It is used to iterate over the corefile's BFD sections and print proper
+   information about memory-mappings.
+
+   ABFD is the bfd used to get the sections.
+   SECT is the current section being "visited".
+   OBJ is not used.  */
+
+static void
+info_core_print_proc_map_non_elf (bfd *abfd, asection *sect, void *obj)
+{
+  /* We're interested in matching sections' names beginning with
+     `load', because they are the sections containing information
+     about the process' memory regions.  */
+  static const char proc_map_match[] = "load";
+  int proc_map_match_size = strlen (proc_map_match);
+  /* We have to know the bitness of this architecture.  */
+  struct gdbarch *gdbarch;
+  int bitness;
+  /* We'll use these later.  They are basically used for iterating
+     over every objfile in the system so that we can find needed
+     information about the memory region being examinated.  */
+  struct obj_section *s;
+  struct objfile *objfile;
+  /* Fields to be printed for the proc map.  */
+  CORE_ADDR start;
+  CORE_ADDR end;
+  CORE_ADDR size;
+  char *filename = "";
+
+  if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0)
+    /* This section is not useful.  */
+    return;
+
+  /* Bitness is important for formatting the text to output.  */
+  gdbarch = gdbarch_from_bfd (abfd);
+  bitness = gdbarch_addr_bit (gdbarch);
+
+  /* Retrieving the section size.  */
+  size = bfd_section_size (bfd, sect);
+
+  start = sect->vma;
+  end = sect->vma + size;
+
+  /* Now begins a new part of the work.  We still don't have complete
+     information about the memory region.  For example, we still need
+     to know the filename which is represented by the region.  Such
+     info can be gathered from the objfile's data structure, and for
+     that we must iterate over all the objsections and check if the
+     objsection's initial address is inside the section we have at hand.
+     If it is, then we can use this specific objsection to obtain the
+     missing data.  */
+  ALL_OBJSECTIONS (objfile, s)
+    {
+      if (objfile->separate_debug_objfile_backlink)
+	continue;
+
+      if (!section_is_overlay (s) && obj_section_addr (s) >= start
+	  && obj_section_addr (s) <= end)
+	{
+	  filename = s->objfile->name;
+	  break;
+	}
+    }
+
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %s\n",
+		     paddress (gdbarch, start),
+		     paddress (gdbarch, end),
+		     paddress (gdbarch, size), filename);
+  else
+    printf_filtered ("  %18s %18s %10s %s\n",
+		     paddress (gdbarch, start),
+		     paddress (gdbarch, end),
+		     paddress (gdbarch, size), filename);
+}
+
+/* Helper function for `info_core_print_core_map' which handles objects
+   in the ELF format.  */
+
+static void
+info_core_print_core_map_elf (void)
+{
+#ifdef HAVE_ELF
+  int bitness;
+  unsigned int n_segs;
+  Elf_Internal_Phdr *p;
+  struct gdbarch *gdbarch = gdbarch_from_bfd (core_bfd);
+
+  /* Bitness is important when formatting the text to be printed.  */
+  bitness = gdbarch_addr_bit (gdbarch);
+
+  p = elf_tdata (core_bfd)->phdr;
+  if (!p)
+    error (_("Could not obtain mapped addresses."));
+
+  printf_filtered (_("Mapped address spaces:\n\n"));
+  if (bitness == 32)
+    printf_filtered ("\t%10s %10s %10s %s\n",
+		     "Start Address",
+		     "  End Address",
+		     "      Size", "objfile");
+  else
+    printf_filtered ("  %18s %18s %10s %s\n",
+		     "Start Address",
+		     "  End Address",
+		     "      Size", "objfile");
+
+  for (n_segs = elf_elfheader (core_bfd)->e_phnum;
+       n_segs > 0; n_segs--, p++)
+    {
+      /* These are basically used for iterating over every objfile in
+	 the system so that we can find needed information about the
+	 memory region being examinated.  */
+      struct obj_section *s;
+      struct objfile *objfile;
+      /* Information about the segment.  */
+      CORE_ADDR start;
+      CORE_ADDR end;
+      CORE_ADDR size;
+      /* File associated with this memory region.  */
+      char *filename = "";
+
+      if (p->p_type != PT_LOAD)
+	/* We are only interested in PT_LOAD segments.  */
+	continue;
+
+      start = p->p_vaddr;
+      size = p->p_memsz;
+      end = start + size;
+
+      ALL_OBJSECTIONS (objfile, s)
+	{
+	  if (objfile->separate_debug_objfile_backlink)
+	    continue;
+
+	  if (!section_is_overlay (s) && obj_section_addr (s) >= start
+	      && obj_section_addr (s) <= end)
+	    {
+	      filename = s->objfile->name;
+	      break;
+	    }
+	}
+
+      if (bitness == 32)
+	printf_filtered ("\t%10s %10s %10s %s\n",
+			 paddress (gdbarch, start),
+			 paddress (gdbarch, end),
+			 paddress (gdbarch, size), filename);
+      else
+	printf_filtered ("  %18s %18s %10s %s\n",
+			 paddress (gdbarch, start),
+			 paddress (gdbarch, end),
+			 paddress (gdbarch, size), filename);
+    }
+#else
+  error (_("Your system does not support ELF format."));
+#endif /* HAVE_ELF */
+}
+
+/* Implement the `info core map' command.  */
+
+static void
+info_core_print_core_map (void)
+{
+  gdb_assert (core_bfd != NULL);
+
+  if (bfd_get_flavour (core_bfd) == bfd_target_elf_flavour)
+    info_core_print_core_map_elf ();
+  else
+    bfd_map_over_sections (core_bfd,
+			   info_core_print_proc_map_non_elf,
+			   NULL);
+}
+
+/* Implement the `info core' command.  */
+
+static void
+info_core_cmd_1 (char *args, enum info_core_what what, int from_tty)
+{
+  char **argv = NULL;
+  int mappings_f = (what == IC_MAPPINGS || what == IC_ALL);
+  int exe_f = (what == IC_MINIMAL || what == IC_EXE || what == IC_ALL);
+
+  if (!core_bfd)
+    error (_("You are not using a corefile at the moment."));
+
+  if (exe_f)
+    info_core_print_core_exe ();
+
+  if (mappings_f)
+    info_core_print_core_map ();
+}
+
+/* Implement `info core' without parameters.  */
+
+static void
+info_core_cmd (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_MINIMAL, from_tty);
+}
+
+/* Implement `info core mappings'.  */
+
+static void
+info_core_cmd_mappings (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_MAPPINGS, from_tty);
+}
+
+/* Implement `info core exe'.  */
+
+static void
+info_core_cmd_exe (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_EXE, from_tty);
+}
+
+/* Implement `info core all'.  */
+
+static void
+info_core_cmd_all (char *args, int from_tty)
+{
+  info_core_cmd_1 (args, IC_ALL, from_tty);
+}
+
 /* If there are two or more functions that wish to hook into
    exec_file_command, this function will call all of the hook
    functions.  */
@@ -449,6 +716,26 @@ void
 _initialize_core (void)
 {
   struct cmd_list_element *c;
+  static struct cmd_list_element *info_core_cmdlist;
+
+  add_prefix_cmd ("core", class_info, info_core_cmd,
+		  _("\
+Show information about a corefile.\n\
+The command uses the corefile loaded."),
+		  &info_core_cmdlist, "info core ",
+		  1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, info_core_cmd_mappings, _("\
+List of mapped memory regions."),
+	   &info_core_cmdlist);
+
+  add_cmd ("exe", class_info, info_core_cmd_exe, _("\
+List absolute filename for executable which generated the corefile."),
+	   &info_core_cmdlist);
+
+  add_cmd ("all", class_info, info_core_cmd_all, _("\
+List all available corefile information."),
+	   &info_core_cmdlist);
 
   c = add_cmd ("core-file", class_files, core_file_command, _("\
 Use FILE as core dump for examining memory and registers.\n\
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f4f7f1e..eb2bdc8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17885,6 +17885,62 @@ processes and all the threads within each process.
 For QNX Neutrino only, this command displays the list of all mapinfos.
 @end table
 
+@node Process Information from Core Dump File
+@subsection Process Information from Core Dump File
+@cindex examine core dump file process information
+@cindex process info via core dump file
+
+If your system supports the generation of core dump files (core files), you
+can use them to obtain information about processes.  For that, you can use
+the command @code{info core} inside @value{GDBN} to report information like
+the memory mappings of the process when the core dump was generated.
+@code{info core} works only on systems that support core dump files, and only
+when you are using a core dump file inside @value{GDBN}.
+
+@xref{Core File Generation}, for information on how to generate core dump
+files inside @value{GDBN}.  @xref{Files}, for information on invoking
+@value{GDBN} in the post-mortem debugging mode.
+
+@table @code
+@kindex info core
+@cindex core dump file, process information
+@item info core
+@itemx info core mappings
+@cindex memory address space mappings inside a core dump file
+Report the memory address ranges accessible in the core dump file.  Assuming
+you have a core dump file and it is loaded into @value{GDBN}, the output of
+the command will be similar to:
+
+@smallexample
+(@value{GDBP}) info core mappings
+Mapped address spaces:
+
+  Start Addr      End Addr      Size objfile
+    0x400000      0x401000    0x1000 /tmp/a.out
+    0x600000      0x601000    0x1000 /tmp/a.out
+0x397de00000  0x397de1f000   0x1f000 /usr/lib/debug/lib/ld.so
+0x397e01e000  0x397e01f000    0x1000 /usr/lib/debug/lib/ld.so
+0x397e01f000  0x397e020000    0x1000 /usr/lib/debug/lib/ld.so
+0x397e020000  0x397e021000    0x1000 /usr/lib/debug/lib/ld.so
+0x397e200000  0x397e391000  0x191000 /usr/lib/debug/lib/libc.so
+0x397e591000  0x397e595000    0x4000 /usr/lib/debug/lib/libc.so
+0x397e595000  0x397e596000    0x1000 /usr/lib/debug/lib/libc.so
+0x397e596000  0x397e59c000    0x6000
+@end smallexample
+
+@item info core exe
+Show the filename of the process that generated this core dump file.
+
+@smallexample
+(@value{GDBP}) info core exe
+exe = '/tmp/a.out'
+@end smallexample
+
+@item info core all
+Show all the information about the core dump file described under all of
+the above @code{info core} subcommands.
+@end table
+
 @node DJGPP Native
 @subsection Features for Debugging @sc{djgpp} Programs
 @cindex @sc{djgpp} debugging
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
index 5b0cdf1..364a018 100644
--- a/gdb/testsuite/gdb.base/corefile.exp
+++ b/gdb/testsuite/gdb.base/corefile.exp
@@ -171,6 +171,13 @@ gdb_test_multiple "x/8bd buf2" "$test" {
     }
 }
 
+# Test the `info core mappings' command.
+set ws "\[ \t\]+"
+set test "test info core mappings"
+gdb_test "info core mappings" \
+	"Mapped address spaces:.*${hex}${ws}${hex}${ws}${hex}.*" \
+	$test
+
 # test reinit_frame_cache
 
 gdb_load ${binfile}

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH] Implement new `info core mappings' command
  2011-11-16  4:10               ` Sergio Durigan Junior
@ 2011-11-21 16:15                 ` Sergio Durigan Junior
  2011-11-23 16:32                   ` [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command) Ulrich Weigand
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-11-21 16:15 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Sergio Durigan Junior <sergiodj@redhat.com> writes:

> Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
>> On Tue, 08 Nov 2011 02:48:54 +0100, Sergio Durigan Junior wrote:
>>> > On Thu, 03 Nov 2011 21:00:39 +0100, Sergio Durigan Junior wrote:
>>> > For ELF core files you should rather check also the ELF segments in
>>> > objfiles->obfd and verify it is fully covered.
>> [...]
>>> This one is giving me headaches...
>>
>> So I understand in some corner cases without ABRT `info core mappings' may be
>> useful but I no longer find too much interest in it myself and some
>> approximate file suggestion may be just good enough there.  After all the
>> whole information about where is which file mapped is just an approximate
>> suggestion by GDB anyway.
>
> Ok, so I would like to ask for another round of review of this patch
> then.  I am aware of Ulrich's work towards a new `info mappings'
> command, but since I've got no response from him yet, I decided to
> continue my efforts here.

Ping.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-11-21 16:15                 ` Sergio Durigan Junior
@ 2011-11-23 16:32                   ` Ulrich Weigand
  2011-11-23 23:37                     ` Sergio Durigan Junior
  2011-12-05 12:59                     ` Pedro Alves
  0 siblings, 2 replies; 83+ messages in thread
From: Ulrich Weigand @ 2011-11-23 16:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: jan.kratochvil, pedro, sergiodj

Sergio Durigan Junior <sergiodj@redhat.com> writes:
> > Ok, so I would like to ask for another round of review of this patch
> > then.  I am aware of Ulrich's work towards a new `info mappings'
> > command, but since I've got no response from him yet, I decided to
> > continue my efforts here.
> 
> Ping.

First of all, sorry for the late reply.  I ran into some issues with
implementing the proposed "info mappings" and then got side-tracked ...

Anyway, here's my current thoughts on the issues and some options on
how to move forward.


Today we have the following set of commands:

- generate-core-file

This uses the target_find_memory_regions callback, which is implemented
on Linux native by reading /proc/.../maps.   My pending patch would have
implemented this callback on remote as well, via a new packet type
qXfer:process-map:read, implemented on Linux gdbserver by reading
/proc/.../maps

- info proc ...  (in particular, info proc mappings)

This is implemented on Linux native target only, where it reads from
/proc directly.   Note that:
* this reads a variety of other files beyond /proc/.../maps
* it can actually read from a completely different process
  (info proc takes an optional PID argument)

(There is also a separate implementation of info proc for procfs
targets, i.e. Solaris, Irix, Tru64).

- info core ... (info core mappings and info core exe)

This would be implemented by Sergio's patch, and available for
core file targets only (any platform).   It would support only
"exe" and "mappings", and only the current core file.


This state of affairs, even assuming both my and Sergio's pending
patch sets were applied, has a couple of drawbacks:

- there is still no "info proc mappings" like command for the remote
  target, even if the remote side runs gdbserver on Linux

- there is still code duplication between the "info proc mappings"
  and target_find_memory_regions implementations in linux-nat.c


To fix these, I had been thinking along the lines of implementing
the following set of features ("Option 1"):

a) Extend target_find_memory_regions to provide mapped file names
   This requires extending the implementation in linux-nat.c, and
   updating other existing implementations and users.

b) Implement target_find_memory_regions for remote targets
   This would use xfer with a new object type TARGET_OBJECT_PROCESS_MAP,
   implemented via a packet type qXfer:process-map:read providing a new
   XML formatted <process-map>.  Implementation on gdbserver in my patch.

c) Implement target_find_memory_regions in corefile.c
   This would use techniques similar to Sergio's current patch.

d) Implement new "info mappings" in core GDB
   This would be independent of existing "info proc" commands.  It would
   be implemented across all targets, and simply call into the (newly
   extended) target_find_memory_regions to get its data.


This would fix the first of the two problems mentioned above, in that
we now also have a working "info mappings" with remote gdbserver targets.

However, we still have code duplication; in fact the duplication is now
even user-visible in the sense that we now have a generic "info mappings"
in addition to the Linux-specific "info proc mappings".

Another drawback is that we do not have anything like Sergio's proposed
"info core exe" command; nor do have anything like "info proc ..." for
any other the *other* commands except "mappings" for remote targets.

Finally, as a (very minor) drawback: in non-XML builds of GDB, the
"info mappings" command would not work with remote targets.


I have been thinking about ways to address these, and come up with one
that would basically export arbitrary /proc files via xfer ("Option 2"):

a) Implement TARGET_OBJECT_PROC xfer object.
   This would use the name of the /proc file as "Annex" (e.g. "maps" /
   "exe" / "cmdline" ...).  On Linux native targets, this can be directly
   implemented via reads from /proc.  For remote targets, this would be
   implemented via a new qXfer:proc:read packet which simply returns raw
   contents of the requested /proc file (no XML format required).  For
   core file targets, we could synthesize Linux /proc/.../maps and
   /proc/.../exe contents via something like Sergio's patch.

b) Implement gdbarch target_find_memory_regions fallback
   This can be implemented on Linux targets (linux-tdep.c) via reading
   TARGET_OBJECT_PROC annex "maps", which would then automatically work
   for native, remote, and core file targets.  The implementation in
   linux-nat.c would then be superfluous.

c) Implement generic "info proc ..." command
   This would call out to a gdbarch architecture-specific implementation.
   (We'd need to take care that on procfs targets, we still use the
   original implementation in procfs.c instead of the generic one.)
   A Linux (linux-tdep.c) implementation of that callback would then use
   TARGET_OBJECT_PROC xfers (and thus work native, remote, and core).
   This would make the linux-nat.c implementation superfluous.


This fixes all the drawbacks mentioned with Option 1 above: there are
no new commands, no more code duplication, we support "info proc exe"
for core files, and we don't even require XML.

However, there are still problems with this option:

- "info proc mappings" and "info proc exe" would work on core files,
  but only *Linux* core files -- at least until other targets implement
  equivalent support.  Sergio's "info core ..." would work anywhere.

- "info proc ..." would lose the possibility to query properties of
  *other* processes except the current one (i.e. the "info proc PID"
  variant could no longer be supported)


The first problem doesn't look really serious to me: if we wouldn't
support "info proc" on a native target, it doesn't seem important
to support it on a core file produced on that target (in particular
if the information we can synthesize is rather sparse anyway).

The second problem also may not be really serious any more: with
current GDB, the user could always use multi-inferior support to 
(temporarily) attach to the process they want to see info about,
instead of specifying the PID in the command.  However, this would
indeed reflect a UI change ...


There is a variant of Option 2 that would actually solve that latter
problem as well: we might encode a target PID in the TARGET_OBJECT_PROC
request, e.g. by using "PID/maps" instead of plain "maps" as the Annex.

(As minor variations, we could keep TARGET_OBJECT_PROC as-is and add
a new TARGET_OBJECT_REMOTE_PROC that takes the PID argument.)

The only drawback of this method seems to be that it would introduce
a somewhat "alien" remote protocol packet type: all the xfer commands
usually refer to the current inferior, not some random other process ...


I'd really appreciate thoughts / suggestions on whether the above
drawbacks are acceptable, and which option we should proceed with.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-11-23 16:32                   ` [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command) Ulrich Weigand
@ 2011-11-23 23:37                     ` Sergio Durigan Junior
  2011-12-01 19:51                       ` Ulrich Weigand
  2011-12-05 12:59                     ` Pedro Alves
  1 sibling, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2011-11-23 23:37 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, pedro

Hi Ulrich,

"Ulrich Weigand" <uweigand@de.ibm.com> writes:

> Sergio Durigan Junior <sergiodj@redhat.com> writes:
>> > Ok, so I would like to ask for another round of review of this patch
>> > then.  I am aware of Ulrich's work towards a new `info mappings'
>> > command, but since I've got no response from him yet, I decided to
>> > continue my efforts here.
>> 
>> Ping.
>
> First of all, sorry for the late reply.  I ran into some issues with
> implementing the proposed "info mappings" and then got side-tracked
> ...

No problem.

> Anyway, here's my current thoughts on the issues and some options on
> how to move forward.

After reading the message at least three times, I like your approach in
general.  It seems a lot cleaner than what is current implemented.  Only
a few comments.

> Today we have the following set of commands:
>
> - generate-core-file
>
> This uses the target_find_memory_regions callback, which is implemented
> on Linux native by reading /proc/.../maps.   My pending patch would have
> implemented this callback on remote as well, via a new packet type
> qXfer:process-map:read, implemented on Linux gdbserver by reading
> /proc/.../maps
>
> - info proc ...  (in particular, info proc mappings)
>
> This is implemented on Linux native target only, where it reads from
> /proc directly.   Note that:
> * this reads a variety of other files beyond /proc/.../maps
> * it can actually read from a completely different process
>   (info proc takes an optional PID argument)
>
> (There is also a separate implementation of info proc for procfs
> targets, i.e. Solaris, Irix, Tru64).
>
> - info core ... (info core mappings and info core exe)
>
> This would be implemented by Sergio's patch, and available for
> core file targets only (any platform).   It would support only
> "exe" and "mappings", and only the current core file.

Maybe this is obvious, but I believe the patch can be (easily?) extended
in order to support other core files than the current one.  Anyway, this
is probably not important now.

> This state of affairs, even assuming both my and Sergio's pending
> patch sets were applied, has a couple of drawbacks:
>
> - there is still no "info proc mappings" like command for the remote
>   target, even if the remote side runs gdbserver on Linux
>
> - there is still code duplication between the "info proc mappings"
>   and target_find_memory_regions implementations in linux-nat.c
>
>
> To fix these, I had been thinking along the lines of implementing
> the following set of features ("Option 1"):
>
> a) Extend target_find_memory_regions to provide mapped file names
>    This requires extending the implementation in linux-nat.c, and
>    updating other existing implementations and users.
>
> b) Implement target_find_memory_regions for remote targets
>    This would use xfer with a new object type TARGET_OBJECT_PROCESS_MAP,
>    implemented via a packet type qXfer:process-map:read providing a new
>    XML formatted <process-map>.  Implementation on gdbserver in my patch.
>
> c) Implement target_find_memory_regions in corefile.c
>    This would use techniques similar to Sergio's current patch.
>
> d) Implement new "info mappings" in core GDB
>    This would be independent of existing "info proc" commands.  It would
>    be implemented across all targets, and simply call into the (newly
>    extended) target_find_memory_regions to get its data.
>
>
> This would fix the first of the two problems mentioned above, in that
> we now also have a working "info mappings" with remote gdbserver targets.
>
> However, we still have code duplication; in fact the duplication is now
> even user-visible in the sense that we now have a generic "info mappings"
> in addition to the Linux-specific "info proc mappings".
>
> Another drawback is that we do not have anything like Sergio's proposed
> "info core exe" command; nor do have anything like "info proc ..." for
> any other the *other* commands except "mappings" for remote targets.
>
> Finally, as a (very minor) drawback: in non-XML builds of GDB, the
> "info mappings" command would not work with remote targets.
>
>
> I have been thinking about ways to address these, and come up with one
> that would basically export arbitrary /proc files via xfer ("Option 2"):
>
> a) Implement TARGET_OBJECT_PROC xfer object.
>    This would use the name of the /proc file as "Annex" (e.g. "maps" /
>    "exe" / "cmdline" ...).  On Linux native targets, this can be directly
>    implemented via reads from /proc.  For remote targets, this would be
>    implemented via a new qXfer:proc:read packet which simply returns raw
>    contents of the requested /proc file (no XML format required).  For
>    core file targets, we could synthesize Linux /proc/.../maps and
>    /proc/.../exe contents via something like Sergio's patch.
>
> b) Implement gdbarch target_find_memory_regions fallback
>    This can be implemented on Linux targets (linux-tdep.c) via reading
>    TARGET_OBJECT_PROC annex "maps", which would then automatically work
>    for native, remote, and core file targets.  The implementation in
>    linux-nat.c would then be superfluous.
>
> c) Implement generic "info proc ..." command
>    This would call out to a gdbarch architecture-specific implementation.
>    (We'd need to take care that on procfs targets, we still use the
>    original implementation in procfs.c instead of the generic one.)
>    A Linux (linux-tdep.c) implementation of that callback would then use
>    TARGET_OBJECT_PROC xfers (and thus work native, remote, and core).
>    This would make the linux-nat.c implementation superfluous.
>
>
> This fixes all the drawbacks mentioned with Option 1 above: there are
> no new commands, no more code duplication, we support "info proc exe"
> for core files, and we don't even require XML.
>
> However, there are still problems with this option:
>
> - "info proc mappings" and "info proc exe" would work on core files,
>   but only *Linux* core files -- at least until other targets implement
>   equivalent support.  Sergio's "info core ..." would work anywhere.
>
> - "info proc ..." would lose the possibility to query properties of
>   *other* processes except the current one (i.e. the "info proc PID"
>   variant could no longer be supported)

This last drawback, as explained later by you, is not a big one IMO.

> The first problem doesn't look really serious to me: if we wouldn't
> support "info proc" on a native target, it doesn't seem important
> to support it on a core file produced on that target (in particular
> if the information we can synthesize is rather sparse anyway).
>
> The second problem also may not be really serious any more: with
> current GDB, the user could always use multi-inferior support to 
> (temporarily) attach to the process they want to see info about,
> instead of specifying the PID in the command.  However, this would
> indeed reflect a UI change ...
>
>
> There is a variant of Option 2 that would actually solve that latter
> problem as well: we might encode a target PID in the TARGET_OBJECT_PROC
> request, e.g. by using "PID/maps" instead of plain "maps" as the Annex.
>
> (As minor variations, we could keep TARGET_OBJECT_PROC as-is and add
> a new TARGET_OBJECT_REMOTE_PROC that takes the PID argument.)
>
> The only drawback of this method seems to be that it would introduce
> a somewhat "alien" remote protocol packet type: all the xfer commands
> usually refer to the current inferior, not some random other process
> ...

No, I believe we should not follow this path.  Being able to display the
memory mapping of one process while debugging another is not something
used that often, I think.  Also, there is always the possibility to use
the multi-inferior feature as you mentioned above.  This probably
deserves a mention in the documentation, probably.

Thanks,

Sergio.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-11-23 23:37                     ` Sergio Durigan Junior
@ 2011-12-01 19:51                       ` Ulrich Weigand
  0 siblings, 0 replies; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-01 19:51 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, jan.kratochvil, pedro

Hi Sergio,

> "Ulrich Weigand" <uweigand@de.ibm.com> writes:
> > Anyway, here's my current thoughts on the issues and some options on
> > how to move forward.
> 
> After reading the message at least three times, I like your approach in
> general.  It seems a lot cleaner than what is current implemented.  Only
> a few comments.

Thanks for your feedback!  I've just posted a series of patches
implementing "Option 2".  While this does not yet include any attempt
to provide TARGET_OBJECT_PROC for core files, this should hopefully
be relatively straightforward to implement ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-11-23 16:32                   ` [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command) Ulrich Weigand
  2011-11-23 23:37                     ` Sergio Durigan Junior
@ 2011-12-05 12:59                     ` Pedro Alves
  2011-12-05 15:02                       ` Ulrich Weigand
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2011-12-05 12:59 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

Hi Ulrich, sorry for the delay.  I haven't managed to read your patches yet.
I'll reaply here first.

On Wednesday 23 November 2011 16:32:08, Ulrich Weigand wrote:

> I'd really appreciate thoughts / suggestions on whether the above
> drawbacks are acceptable, and which option we should proceed with.

First, the reason Sergio added "info mappings" instead of making
"info proc mappings" work for core files, was that using "info proc"
for cores was objected.  I'm personally okay with it, but I think
that should be understood as not being a limitation of the design.

I have to say that I have reservations on this new TARGET_OBJECT_PROC
option.  It adds yet another generic abstraction (it almost looks like
TARGET_OBJECT_OSDATA reinvented), yet the data it sends over is not
really structured.  This maps nicely on linux, but, e.g, on procfs targets,
you have a bunch of different /proc implementations, it can actually be
awkward, in that you may need to translate whatever the real /proc/pid/foo
gives you into a format gdb expects.  The answer to that seems to be that GDB
will install a gdbarch handler for each OS that understands 
/proc/pid/foo for the target OS, but that means that either or both of core
gdb and the target (can result in weird wrong turns, if we add coping to
both ends) will have to keep up with whatever format changes happen
between OS revisions on the target side instead of being given a
structured, abstracted and simplified view (that could in turn be easily
marshalled in structured form to MI or python, if so desired).  And then
there's no default gdb-side gdbarch implementation, so GDB needs to be
aware of the random embedded OSs to be able to support "info proc foo".  
A structured format means that its definitely the target that gets to keep up.

This is not a NAK, but I'm just saying I'm not fully convinced yet.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-05 12:59                     ` Pedro Alves
@ 2011-12-05 15:02                       ` Ulrich Weigand
  2011-12-06 16:01                         ` Pedro Alves
  0 siblings, 1 reply; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-05 15:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:

> Hi Ulrich, sorry for the delay.  I haven't managed to read your patches yet.
> I'll reaply here first.

Thanks for your comments!

> First, the reason Sergio added "info mappings" instead of making
> "info proc mappings" work for core files, was that using "info proc"
> for cores was objected.  I'm personally okay with it, but I think
> that should be understood as not being a limitation of the design.

Actually, Sergio's latest patches added "info core" with a number
of subcommands, including "info core mappings".

I didn't really like this.  IMO the underlying problem with "info proc"
is that it is a target-specific command in the first place.  If you want
to look at a process' memory map, you don't really care whether the
process is running natively, or running on a remote machine accesses
via gdbserver, or even if you're just looking at a core file.  As a
user, I don't really see why looking at the memory map should require
use of different commands depending on the particular mode of operation,
or even why it shouldn't work at all in some of those modes.

"info proc" doesn't work that way; it is completely tied to native
operation.  Adding an "info core" does make some information available
for core files, but it doesn't really solve the underlying problem:
you still need to remember to use a different command, and even so
it doesn't work for remote/gdbserver targets at all.


That's why my suggestion was to instead move "info proc" to be
target-independent.  That is to say, it would still show Linux-specific
information about a process, but it would no longer depend on whether
you look at that Linux process natively, remotely, or post-mortem.

(Of course in the core file case, that goal can only reached approximately,
since some information is simply not available -- but that situation also
applies in some other aspects to core files ...)


Now, instead of this change to "info proc", we could add a new
"info mappings" command.  (Note that this would correspond to the
"option 1" in my email.)   This would have the same advantage of
providing the same command for all modes of operation, and could
actually be even more general, beyond just Linux targets, to cover
any target that has a notion of memory-mapping files.

However, at least in my opinion, this option still has drawbacks:
Users today are used to "info proc mappings".  Should we remove that
command?  Or else forward it to the new "info mappings"?   But in either
case there is now a disconnect to the other "info proc" commands; why
should "info proc mappings" work on remote/gdbserver, but not the other
commands?  In the end, this still doesn't solve the fundamental problem
of having a native-target-implemented command "info proc".

 
> I have to say that I have reservations on this new TARGET_OBJECT_PROC
> option.  It adds yet another generic abstraction (it almost looks like
> TARGET_OBJECT_OSDATA reinvented), yet the data it sends over is not
> really structured.  This maps nicely on linux, but, e.g, on procfs targets,
> you have a bunch of different /proc implementations, it can actually be
> awkward, in that you may need to translate whatever the real /proc/pid/foo
> gives you into a format gdb expects.  The answer to that seems to be that GDB
> will install a gdbarch handler for each OS that understands 
> /proc/pid/foo for the target OS, but that means that either or both of core
> gdb and the target (can result in weird wrong turns, if we add coping to
> both ends) will have to keep up with whatever format changes happen
> between OS revisions on the target side instead of being given a
> structured, abstracted and simplified view (that could in turn be easily
> marshalled in structured form to MI or python, if so desired).  And then
> there's no default gdb-side gdbarch implementation, so GDB needs to be
> aware of the random embedded OSs to be able to support "info proc foo".  
> A structured format means that its definitely the target that gets to keep up.

Well, IMO there's two "flavours" of target objects, if you will.  Some objects
are completely generic, fully defined by GDB -usually via XML-, and implemented
(or implementable) across all target machines and operating systems.

But there is another class of target objects whose contents are not generic,
but specific to a particular architecture and/or operating system; they are
still implemented as target object in order to give architecture code a way
to get at those contents in a homogeneous way no matter whether GDB operates
in native, remote, or core file mode.  This class includes things like
TARGET_OBJECT_SPU, TARGET_OBJECT_WCOOKIE, TARGET_OBJECT_DARWIN_DYLD_INFO,
and probably something like the new TARGET_OBJECT_LIBRARIES_SVR4 ...

In my mind, the proposed TARGET_OBJECT_PROC would fall into the second
category, that is, it provides access to pre-existing, operating-system
defined contents, while simply abstracting the means of delivery.  In
particular, I would not expect the "provider side" (Linux native target
or gdbserver code) to ever implement any sort of "conversion" of the
contents.  If there ever should be changes to the contents of /proc
files, the task of adapting to those changes should lie solely on
the gdbarch code that consumes the TARGET_OBJECT_PROC objects.

Of course, as you say, this means that TARGET_OBJECT_PROC really only
can ever be consumed by OS-specific, usually gdbarch code.  (But that's
still better than having *native-target-only* code IMO.)

I wouldn't mind renaming the object to TARGET_OBJECT_LINUX_PROC to make
the intention about the objects contents clearer.  (I thought that maybe
other procfs targets could also use TARGET_OBJECT_PROC, but since of
course the contents would be different, it might be better to use a
new object type if and when we ever do that ...)


> This is not a NAK, but I'm just saying I'm not fully convinced yet.

Did this help convince you? :-)

B.t.w. for the purpose I'm immediately interested in myself right now,
which is to provide for remote/gdbserver core file generation, either
my "option 1" via TARGET_OBJECT_ADDRESS_MAP or my "option 2" via
TARGET_OBJECT_PROC would work just as well, and I've already implemented
code for either ...  So I'm not really very tied to TARGET_OBJECT_PROC;
I've just come to thinking this would be the more general solution by
getting rid of the native-target-implemented "info proc".

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-05 15:02                       ` Ulrich Weigand
@ 2011-12-06 16:01                         ` Pedro Alves
  2011-12-06 17:19                           ` Ulrich Weigand
  0 siblings, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2011-12-06 16:01 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

On Monday 05 December 2011 14:52:04, Ulrich Weigand wrote:
> Pedro Alves wrote:
> 
> > Hi Ulrich, sorry for the delay.  I haven't managed to read your patches yet.
> > I'll reaply here first.
> 
> Thanks for your comments!
> 
> > First, the reason Sergio added "info mappings" instead of making
> > "info proc mappings" work for core files, was that using "info proc"
> > for cores was objected.  I'm personally okay with it, but I think
> > that should be understood as not being a limitation of the design.
> 
> Actually, Sergio's latest patches added "info core" with a number
> of subcommands, including "info core mappings".
> 
> I didn't really like this.  IMO the underlying problem with "info proc"
> is that it is a target-specific command in the first place.  If you want
> to look at a process' memory map, you don't really care whether the
> process is running natively, or running on a remote machine accesses
> via gdbserver, or even if you're just looking at a core file.  As a
> user, I don't really see why looking at the memory map should require
> use of different commands depending on the particular mode of operation,
> or even why it shouldn't work at all in some of those modes.
> 
> "info proc" doesn't work that way; it is completely tied to native
> operation.  Adding an "info core" does make some information available
> for core files, but it doesn't really solve the underlying problem:
> you still need to remember to use a different command, and even so
> it doesn't work for remote/gdbserver targets at all.

IIRC, the rationale given for the objections was that "info proc" was
originally intended as just a frontend for /proc (hence it accepting
PIDs not being debugged), and, that there are other core-specific info
bits that we could attach as "info core" subcommands.
Playing devil's advicate, under this perpective, another way to look
at it, is to consider that "info proc PID" should still read /proc
info from the running system, even when debugging a core, or just an exec.

> That's why my suggestion was to instead move "info proc" to be
> target-independent.  That is to say, it would still show Linux-specific
> information about a process, but it would no longer depend on whether
> you look at that Linux process natively, remotely, or post-mortem.

One could argue that generic info like that should be under
the "inferior" moniker, not "process".

> (Of course in the core file case, that goal can only reached approximately,
> since some information is simply not available -- but that situation also
> applies in some other aspects to core files ...)
> 
> 
> Now, instead of this change to "info proc", we could add a new
> "info mappings" command.  (Note that this would correspond to the
> "option 1" in my email.)   This would have the same advantage of
> providing the same command for all modes of operation, and could
> actually be even more general, beyond just Linux targets, to cover
> any target that has a notion of memory-mapping files.
> 
> However, at least in my opinion, this option still has drawbacks:
> Users today are used to "info proc mappings".  Should we remove that
> command?  Or else forward it to the new "info mappings"?   But in either
> case there is now a disconnect to the other "info proc" commands; why
> should "info proc mappings" work on remote/gdbserver, but not the other
> commands?  In the end, this still doesn't solve the fundamental problem
> of having a native-target-implemented command "info proc".

I definitely agree that "info proc FOO" should be forwarded.  Debugging
against remote or native should ideally provide the same experience,
you're just connected to a different host (localhost or remote).

> > I have to say that I have reservations on this new TARGET_OBJECT_PROC
> > option.  It adds yet another generic abstraction (it almost looks like
> > TARGET_OBJECT_OSDATA reinvented), yet the data it sends over is not
> > really structured.  This maps nicely on linux, but, e.g, on procfs targets,
> > you have a bunch of different /proc implementations, it can actually be
> > awkward, in that you may need to translate whatever the real /proc/pid/foo
> > gives you into a format gdb expects.  The answer to that seems to be that GDB
> > will install a gdbarch handler for each OS that understands 
> > /proc/pid/foo for the target OS, but that means that either or both of core
> > gdb and the target (can result in weird wrong turns, if we add coping to
> > both ends) will have to keep up with whatever format changes happen
> > between OS revisions on the target side instead of being given a
> > structured, abstracted and simplified view (that could in turn be easily
> > marshalled in structured form to MI or python, if so desired).  And then
> > there's no default gdb-side gdbarch implementation, so GDB needs to be
> > aware of the random embedded OSs to be able to support "info proc foo".  
> > A structured format means that its definitely the target that gets to keep up.
> 
> Well, IMO there's two "flavours" of target objects, if you will.  Some objects
> are completely generic, fully defined by GDB -usually via XML-, and implemented
> (or implementable) across all target machines and operating systems.
> 
> But there is another class of target objects whose contents are not generic,
> but specific to a particular architecture and/or operating system; they are
> still implemented as target object in order to give architecture code a way
> to get at those contents in a homogeneous way no matter whether GDB operates
> in native, remote, or core file mode.  This class includes things like
> TARGET_OBJECT_SPU, TARGET_OBJECT_WCOOKIE, TARGET_OBJECT_DARWIN_DYLD_INFO,

Right.  Generally, blobs, binary objects.  Descriptive, meta- objects tend
to be xml.

> and probably something like the new TARGET_OBJECT_LIBRARIES_SVR4 ...

(Nope, that's xml.)

> In my mind, the proposed TARGET_OBJECT_PROC would fall into the second
> category, that is, it provides access to pre-existing, operating-system
> defined contents, while simply abstracting the means of delivery.  In
> particular, I would not expect the "provider side" (Linux native target
> or gdbserver code) to ever implement any sort of "conversion" of the
> contents.  If there ever should be changes to the contents of /proc
> files, the task of adapting to those changes should lie solely on
> the gdbarch code that consumes the TARGET_OBJECT_PROC objects.

How are we making "info proc map" work with core files
with this?  I'd imagine the core target falling back to the gdbarch
method, but are we then making the core target synthesize TARGET_OBJECT_PROC
objects for the gdbarch method to consume?  That's where the bit
about "I don't expect the "provider side (...) to ever implement any
sort of "conversion" of the contents" seems to fall short.

> Of course, as you say, this means that TARGET_OBJECT_PROC really only
> can ever be consumed by OS-specific, usually gdbarch code.  (But that's
> still better than having *native-target-only* code IMO.)

If GDB already needs to know what it is reading, then this could also be
implemented by having the gdbarch hook open/read remote:/proc/PID/maps ?
No new target object or packets necessary?  Because I'm not seeing what
TARGET_OBJECT_PROC brings over that (though I'm still confused on how
"info proc map" on cores is meant to be implemented with this).

> I wouldn't mind renaming the object to TARGET_OBJECT_LINUX_PROC to make
> the intention about the objects contents clearer.  (I thought that maybe
> other procfs targets could also use TARGET_OBJECT_PROC, but since of
> course the contents would be different, it might be better to use a
> new object type if and when we ever do that ...)

I think the name is fine.  There's something bugging
me that may affect the decision though.  Up until very recently, the
FOO in "info proc FOO" was more freeform than it is now:

http://sourceware.org/ml/gdb-patches/2011-10/msg00819.html

But IIUC, while the TARGET_OBJECT_PROC object still takes the
FOO to return as annex, the set of possible FOOs (map, exec, etc.)
will now be hardcoded, instead of leaving those to the
backend/target as well.

> 
> 
> > This is not a NAK, but I'm just saying I'm not fully convinced yet.
> 
> Did this help convince you? :-)

Not yet.  :-)

> B.t.w. for the purpose I'm immediately interested in myself right now,
> which is to provide for remote/gdbserver core file generation, either
> my "option 1" via TARGET_OBJECT_ADDRESS_MAP or my "option 2" via
> TARGET_OBJECT_PROC would work just as well, and I've already implemented
> code for either ...  So I'm not really very tied to TARGET_OBJECT_PROC;
> I've just come to thinking this would be the more general solution by
> getting rid of the native-target-implemented "info proc".

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-06 16:01                         ` Pedro Alves
@ 2011-12-06 17:19                           ` Ulrich Weigand
  2011-12-07 16:29                             ` Pedro Alves
  0 siblings, 1 reply; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-06 17:19 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On Monday 05 December 2011 14:52:04, Ulrich Weigand wrote:
> > "info proc" doesn't work that way; it is completely tied to native
> > operation.  Adding an "info core" does make some information available
> > for core files, but it doesn't really solve the underlying problem:
> > you still need to remember to use a different command, and even so
> > it doesn't work for remote/gdbserver targets at all.
> 
> IIRC, the rationale given for the objections was that "info proc" was
> originally intended as just a frontend for /proc (hence it accepting
> PIDs not being debugged), and, that there are other core-specific info
> bits that we could attach as "info core" subcommands.
> Playing devil's advicate, under this perpective, another way to look
> at it, is to consider that "info proc PID" should still read /proc
> info from the running system, even when debugging a core, or just an exec.

Well, that's how "info proc" works today -- it looks at the native system
/proc no matter what inferior you're debugging, even when using a completely
different target (e.g. remote).

It's just that this behaviour seems a bit unexpected to me from a user's
perspective.  Whether the proper fix for this is to re-purpose the
"info proc" command (along the lines of "show me the type of information
about the current inferior that the OS provides about its underlying
process in /proc, no matter how I'm currently accessing it"), or whether
we ought to just leave "info proc" as is and implement some new command.

> > That's why my suggestion was to instead move "info proc" to be
> > target-independent.  That is to say, it would still show Linux-specific
> > information about a process, but it would no longer depend on whether
> > you look at that Linux process natively, remotely, or post-mortem.
> 
> One could argue that generic info like that should be under
> the "inferior" moniker, not "process".

I personally wouldn't really care either way.  But it's probably not a
good idea to provide yet more similar-but-slightly different commands
to confuse the user; IMO we shouldn't have both "info proc mappings"
*and* a new "info inferior mappings" ...

It seems to me that the original user request was along the lines:
users are familar with the "info proc mappings" command and use it
frequently; but the command doesn't work remotely and with core files,
can't we fix that?

> I definitely agree that "info proc FOO" should be forwarded.  Debugging
> against remote or native should ideally provide the same experience,
> you're just connected to a different host (localhost or remote).

Completely agreed.

> > In my mind, the proposed TARGET_OBJECT_PROC would fall into the second
> > category, that is, it provides access to pre-existing, operating-system
> > defined contents, while simply abstracting the means of delivery.  In
> > particular, I would not expect the "provider side" (Linux native target
> > or gdbserver code) to ever implement any sort of "conversion" of the
> > contents.  If there ever should be changes to the contents of /proc
> > files, the task of adapting to those changes should lie solely on
> > the gdbarch code that consumes the TARGET_OBJECT_PROC objects.
> 
> How are we making "info proc map" work with core files
> with this?  I'd imagine the core target falling back to the gdbarch
> method, but are we then making the core target synthesize TARGET_OBJECT_PROC
> objects for the gdbarch method to consume?  That's where the bit
> about "I don't expect the "provider side (...) to ever implement any
> sort of "conversion" of the contents" seems to fall short.

My thoughts for this were for core_xfer_partial to handle the
TARGET_OBJECT_PROC case by calling into a new gdbarch routine
gdbarch_core_xfer_proc or so (along the lines of
gdbarch_core_xfer_shared_libraries).  The linux-tdep implementation
of this would then synthesize /proc/../map contents corresponding
to the core file.

(In the alternative, we could just have a generic gdbarch_core_xfer_partial
routine and move some of the existing platform-specific stuff there.)

It's true that in this case, we would synthesize /proc output, but in
a sense that's just because the kernel didn't provide it --  in theory,
the kernel could put /proc file contents into core file notes, just like
it does e.g. with spufs contents ...

Also, the code synthesizing /proc output would be in one place right
next to the code parsing /proc output, both in linux-tdep.c.  So it
shouldn't be much of a maintenance hazard going forward to make sure
they keep in agreement ...

> > Of course, as you say, this means that TARGET_OBJECT_PROC really only
> > can ever be consumed by OS-specific, usually gdbarch code.  (But that's
> > still better than having *native-target-only* code IMO.)
> 
> If GDB already needs to know what it is reading, then this could also be
> implemented by having the gdbarch hook open/read remote:/proc/PID/maps ?
> No new target object or packets necessary?  Because I'm not seeing what
> TARGET_OBJECT_PROC brings over that (though I'm still confused on how
> "info proc map" on cores is meant to be implemented with this).

For remote, we could do something along those lines (we cannot directly
use "remote:" because this is only implemented for BFD access -- but
we could use the underlying remote_hostio_pread etc. routines).

However, this would mean that gdbarch code would have to know whether or
not it runs on a remote target, or on a Linux native target (we wouldn't
want to access /proc on some system where this isn't available or maybe
does something different).  Also, it wouldn't work for core files.

That's why I'm suggesting separating *accessing* the data (into target
code via TARGET_OBJECT_PROC) from *parsing* the data (into gdbarch code).

[ I guess we could implement TARGET_OBJECT_PROC without a new packet type
but implementing TARGET_OBJECT_PROC xfer in remote.c via remote_hostio_pread.
This makes the assumption that the remote side always has a Linux-style /proc,
however.  Not sure whether we should make that assumption ... ]

> > I wouldn't mind renaming the object to TARGET_OBJECT_LINUX_PROC to make
> > the intention about the objects contents clearer.  (I thought that maybe
> > other procfs targets could also use TARGET_OBJECT_PROC, but since of
> > course the contents would be different, it might be better to use a
> > new object type if and when we ever do that ...)
> 
> I think the name is fine.  There's something bugging
> me that may affect the decision though.  Up until very recently, the
> FOO in "info proc FOO" was more freeform than it is now:
> 
> http://sourceware.org/ml/gdb-patches/2011-10/msg00819.html
> 
> But IIUC, while the TARGET_OBJECT_PROC object still takes the
> FOO to return as annex, the set of possible FOOs (map, exec, etc.)
> will now be hardcoded, instead of leaving those to the
> backend/target as well.

My thoughts were for common code to provide a superset of the
set of subcommands supported by all potential gdbarch backends,
and then have the particular backend reject those it doesn't
support.

I guess we could try to make the list of subcommands itself
dynamic and depend on the current gdbarch.  That might require
some enhancements to the command handling infrastructure, though.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-06 17:19                           ` Ulrich Weigand
@ 2011-12-07 16:29                             ` Pedro Alves
  2011-12-07 17:24                               ` Pedro Alves
  2011-12-07 20:14                               ` Ulrich Weigand
  0 siblings, 2 replies; 83+ messages in thread
From: Pedro Alves @ 2011-12-07 16:29 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

On Tuesday 06 December 2011 16:46:04, Ulrich Weigand wrote:
> Pedro Alves wrote:
> > On Monday 05 December 2011 14:52:04, Ulrich Weigand wrote:

> It seems to me that the original user request was along the lines:
> users are familar with the "info proc mappings" command and use it
> frequently; but the command doesn't work remotely and with core files,
> can't we fix that?

We should read past what users literaly say, and infer what
they really want --- to be able to read the mappings of core
files.  Users get used to what we give them -- info proc is what
only had.  They can get used to whatever else we give them.  :-)

Anyway, I'm just playing the devil's advocate, I actually agree
with "info proc" for cores.  :-)  I think it was useful to have
this part of discussion, so that if/when this goes through, it
won't have gone without being discussed.

> > > In my mind, the proposed TARGET_OBJECT_PROC would fall into the second
> > > category, that is, it provides access to pre-existing, operating-system
> > > defined contents, while simply abstracting the means of delivery.  In
> > > particular, I would not expect the "provider side" (Linux native target
> > > or gdbserver code) to ever implement any sort of "conversion" of the
> > > contents.  If there ever should be changes to the contents of /proc
> > > files, the task of adapting to those changes should lie solely on
> > > the gdbarch code that consumes the TARGET_OBJECT_PROC objects.
> > 
> > How are we making "info proc map" work with core files
> > with this?  I'd imagine the core target falling back to the gdbarch
> > method, but are we then making the core target synthesize TARGET_OBJECT_PROC
> > objects for the gdbarch method to consume?  That's where the bit
> > about "I don't expect the "provider side (...) to ever implement any
> > sort of "conversion" of the contents" seems to fall short.
> 
> My thoughts for this were for core_xfer_partial to handle the
> TARGET_OBJECT_PROC case by calling into a new gdbarch routine
> gdbarch_core_xfer_proc or so (along the lines of
> gdbarch_core_xfer_shared_libraries).  The linux-tdep implementation
> of this would then synthesize /proc/../map contents corresponding
> to the core file.

Okay, as suspected.  I guess I can live with that.

> (In the alternative, we could just have a generic gdbarch_core_xfer_partial
> routine and move some of the existing platform-specific stuff there.)
> 
> It's true that in this case, we would synthesize /proc output, but in
> a sense that's just because the kernel didn't provide it --  in theory,
> the kernel could put /proc file contents into core file notes, just like
> it does e.g. with spufs contents ...

Interesting.  Didn't know that.  Makes some sense.

> Also, the code synthesizing /proc output would be in one place right
> next to the code parsing /proc output, both in linux-tdep.c.  So it
> shouldn't be much of a maintenance hazard going forward to make sure
> they keep in agreement ...
> 
> > > Of course, as you say, this means that TARGET_OBJECT_PROC really only
> > > can ever be consumed by OS-specific, usually gdbarch code.  (But that's
> > > still better than having *native-target-only* code IMO.)
> > 
> > If GDB already needs to know what it is reading, then this could also be
> > implemented by having the gdbarch hook open/read remote:/proc/PID/maps ?
> > No new target object or packets necessary?  Because I'm not seeing what
> > TARGET_OBJECT_PROC brings over that (though I'm still confused on how
> > "info proc map" on cores is meant to be implemented with this).
> 
> For remote, we could do something along those lines (we cannot directly
> use "remote:" because this is only implemented for BFD access -- but
> we could use the underlying remote_hostio_pread etc. routines).

Right, I did not mean to imply "remote:" literally.  
I kind of see "remote:/proc/PID/maps" as a target path mounted
on the host, so "remote:/proc/PID/maps" is a really a host path.
The "/proc/PID/maps" path, what the code in question wants to get at, is
a target path.  I was trying to say is that the gdbarch hook would always
open/read "/proc/PID/maps" from the target, instead of from the host.  On
native targets, that ends up falling back to the host filesystem.  For
remote targets, that would use the existing hostio mechanism, the same
as used by "remote:".  This suggests e.g., a target method to
fully open/read/close a target path and return the file's contents (like
you say), or, alternatively, wrap the hostio mechanism in a
ui-file (through open/read/write/close/... target methods perhaps), and
use that.

> 
> However, this would mean that gdbarch code would have to know whether or
> not it runs on a remote target, or on a Linux native target (we wouldn't
> want to access /proc on some system where this isn't available or maybe
> does something different).  

Not if we design it right.  If we want to read a target path, we just use
a mechanisnm to read a target path.  The fact that on a Linux 
native target that ends up accessing the host filesystem is of concern to
the target backend alone.  It's still a target path.  

(We already have a clear distinction between a host and target path in
some places nowadays.  See e.g., solib.c:solib_find, and its use
of HAS_TARGET_DRIVE_SPEC, IS_TARGET_ABSOLUTE_PATH, etc..)

> Also, it wouldn't work for core files.

I think it would.

> That's why I'm suggesting separating *accessing* the data (into target
> code via TARGET_OBJECT_PROC) from *parsing* the data (into gdbarch code).

Right, but it's still separated with hostio transfers.

> [ I guess we could implement TARGET_OBJECT_PROC without a new packet type
> but implementing TARGET_OBJECT_PROC xfer in remote.c via remote_hostio_pread.
> This makes the assumption that the remote side always has a Linux-style /proc,
> however.  Not sure whether we should make that assumption ... ]

If the OS does has something else entirely, then the gdbarch method will
be aware, because it is the gdbarch method itself that retrieves
the data.  It may even use something completely different, not
based on filesystems at all.  Otherwise, we're back at making targets
fake a file system and proc interface they don't have, where we might
as well return some structured data.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-07 16:29                             ` Pedro Alves
@ 2011-12-07 17:24                               ` Pedro Alves
  2011-12-07 20:14                               ` Ulrich Weigand
  1 sibling, 0 replies; 83+ messages in thread
From: Pedro Alves @ 2011-12-07 17:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand, jan.kratochvil, sergiodj

On Wednesday 07 December 2011 16:24:31, Pedro Alves wrote:
> > For remote, we could do something along those lines (we cannot directly
> > use "remote:" because this is only implemented for BFD access -- but
> > we could use the underlying remote_hostio_pread etc. routines).
> 
> Right, I did not mean to imply "remote:" literally.  
> I kind of see "remote:/proc/PID/maps" as a target path mounted
> on the host, so "remote:/proc/PID/maps" is a really a host path.
> The "/proc/PID/maps" path, what the code in question wants to get at, is
> a target path.  I was trying to say is that the gdbarch hook would always
> open/read "/proc/PID/maps" from the target, instead of from the host.  On
> native targets, that ends up falling back to the host filesystem.  For
> remote targets, that would use the existing hostio mechanism, the same
> as used by "remote:".  This suggests e.g., a target method to
> fully open/read/close a target path and return the file's contents (like
> you say), or, alternatively, wrap the hostio mechanism in a
> ui-file (through open/read/write/close/... target methods perhaps), and
> use that.

BTW, from this perspective, "remote:" would have been
better named "target:" IMO.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-07 16:29                             ` Pedro Alves
  2011-12-07 17:24                               ` Pedro Alves
@ 2011-12-07 20:14                               ` Ulrich Weigand
  2011-12-09 13:28                                 ` Pedro Alves
  2011-12-20 23:08                                 ` Ulrich Weigand
  1 sibling, 2 replies; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-07 20:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On Tuesday 06 December 2011 16:46:04, Ulrich Weigand wrote:
> > Pedro Alves wrote:
> > > On Monday 05 December 2011 14:52:04, Ulrich Weigand wrote:
> 
> > It seems to me that the original user request was along the lines:
> > users are familar with the "info proc mappings" command and use it
> > frequently; but the command doesn't work remotely and with core files,
> > can't we fix that?
> 
> We should read past what users literaly say, and infer what
> they really want --- to be able to read the mappings of core
> files.  Users get used to what we give them -- info proc is what
> only had.  They can get used to whatever else we give them.  :-)
> 
> Anyway, I'm just playing the devil's advocate, I actually agree
> with "info proc" for cores.  :-)  I think it was useful to have
> this part of discussion, so that if/when this goes through, it
> won't have gone without being discussed.

OK, thanks.

> > For remote, we could do something along those lines (we cannot directly
> > use "remote:" because this is only implemented for BFD access -- but
> > we could use the underlying remote_hostio_pread etc. routines).
> 
> Right, I did not mean to imply "remote:" literally.  
> I kind of see "remote:/proc/PID/maps" as a target path mounted
> on the host, so "remote:/proc/PID/maps" is a really a host path.
> The "/proc/PID/maps" path, what the code in question wants to get at, is
> a target path.  I was trying to say is that the gdbarch hook would always
> open/read "/proc/PID/maps" from the target, instead of from the host.  On
> native targets, that ends up falling back to the host filesystem.  For
> remote targets, that would use the existing hostio mechanism, the same
> as used by "remote:".  This suggests e.g., a target method to
> fully open/read/close a target path and return the file's contents (like
> you say), or, alternatively, wrap the hostio mechanism in a
> ui-file (through open/read/write/close/... target methods perhaps), and
> use that.

I see.  It still seems that the target object mechanism should be a good
fit for that; but instead of talking about a specific TARGET_OBJECT_PROC,
we're now talking about a generic TARGET_OBJECT_FILE -- which may have been
part of the original target object design to start with, see e.g. the 
comment in target.h:

  /* Possible future objects: TARGET_OBJECT_FILE, ...  */


> > [ I guess we could implement TARGET_OBJECT_PROC without a new packet type
> > but implementing TARGET_OBJECT_PROC xfer in remote.c via remote_hostio_pread.
> > This makes the assumption that the remote side always has a Linux-style /proc,
> > however.  Not sure whether we should make that assumption ... ]
> 
> If the OS does has something else entirely, then the gdbarch method will
> be aware, because it is the gdbarch method itself that retrieves
> the data.  It may even use something completely different, not
> based on filesystems at all.  Otherwise, we're back at making targets
> fake a file system and proc interface they don't have, where we might
> as well return some structured data.

Hmm, OK.  I agree.  So this option would be to:

- Define a new TARGET_OBJECT_FILE.  The "annex" is simply a full path name
  of a file on the target system.

- Implement its xfer method for native targets, probably in inf-ptrace.c
  (or maybe even as generic default in target.c), via native file I/O.

- Implement its xfer method for remote targets in remote.c, using the
  hostio mechanism (no new packets required).

- Implement its xfer method for core files via a gdbarch callback allowing
  the arch to synthesize contents of arbitrary files.


Note that to fully implement "info proc", we also need to be able to
read the link path names for files that happen to be symbolic links.
For TARGET_OBJECT_PROC, I simply defined the target object that way;
this doesn't really make sense for TARGET_OBJECT_FILE.  So we might
want to add another target object type TARGET_OBJECT_SYMLINK that
provides that capability.  Unfortunately, this does mean we need a
new remote protocol packet, since hostio does not support readlink ...


Pros of this method would be:

- New target objects are quite generic and well-defined.

- "info proc" now can go back to display info about arbitrary processes.

- No new remote protocol packets for TARGET_OBJECT_FILE.


Cons of the method:

- Need new remote protocol packet for TARGET_OBJECT_SYMLINK after all.

- Synthesizing file contents for core files is a bit more awkward, since
  you have to recognize particular /proc/PID/... file names.


The alternative to TARGET_OBJECT_FILE/SYMLINK would be to provide a set
of target_file_... accessor routines that map to native IO for native
targets and hostio for remote targets, again with a gdbarch option to
synthesize file contents from core files.

This would require the exact same set of remote protocol extensions
as the above (i.e. a vFile:readlink or so), and allow the exact same
set of capabilities; this is purely a question of what GDB-internal
interface is preferable.


Thoughts?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-07 20:14                               ` Ulrich Weigand
@ 2011-12-09 13:28                                 ` Pedro Alves
  2011-12-09 14:10                                   ` Pedro Alves
  2011-12-20 23:08                                 ` Ulrich Weigand
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2011-12-09 13:28 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

Hi Ulrich,

sorry for my delays.

On Wednesday 07 December 2011 17:55:29, Ulrich Weigand wrote:
> Pedro Alves wrote:
> > On Tuesday 06 December 2011 16:46:04, Ulrich Weigand wrote:
> > > For remote, we could do something along those lines (we cannot directly
> > > use "remote:" because this is only implemented for BFD access -- but
> > > we could use the underlying remote_hostio_pread etc. routines).
> > 
> > Right, I did not mean to imply "remote:" literally.  
> > I kind of see "remote:/proc/PID/maps" as a target path mounted
> > on the host, so "remote:/proc/PID/maps" is a really a host path.
> > The "/proc/PID/maps" path, what the code in question wants to get at, is
> > a target path.  I was trying to say is that the gdbarch hook would always
> > open/read "/proc/PID/maps" from the target, instead of from the host.  On
> > native targets, that ends up falling back to the host filesystem.  For
> > remote targets, that would use the existing hostio mechanism, the same
> > as used by "remote:".  This suggests e.g., a target method to
> > fully open/read/close a target path and return the file's contents (like
> > you say), or, alternatively, wrap the hostio mechanism in a
> > ui-file (through open/read/write/close/... target methods perhaps), and
> > use that.
> 
> I see.  It still seems that the target object mechanism should be a good
> fit for that; but instead of talking about a specific TARGET_OBJECT_PROC,
> we're now talking about a generic TARGET_OBJECT_FILE -- which may have been
> part of the original target object design to start with, see e.g. the 
> comment in target.h:
> 
>   /* Possible future objects: TARGET_OBJECT_FILE, ...  */

Yeah.  Although, I'm not so sure a target object for reading a file
is a good idea.  The problem with it, is that there's no notion of
"open/session handle" in target objects.  That means that for each
partial transfer of a given target object, that can start at any offset,
and extend for any number of bytes, not necessarily the length of the
object (which might not be known upfront), the backend/server xfer method
needs to open/close the destination object.  If the file changes, or
even if deleted/recreated behind the client's back, the transfer
ends up corrupted.  (e.g., the program is running, and the mappings
change while the xfer is taking place; or, the PID program vanishes
and PID is reused.)

We already take this into consideration in some cases.  E.g., 

common/linux-osdata.c:
static LONGEST
linux_xfer_osdata_processes (gdb_byte *readbuf,
			     ULONGEST offset, LONGEST len)
{
  /* We make the process list snapshot when the object starts to be read.  */
  static const char *buf;
  static LONGEST len_avail = -1;
  static struct buffer buffer;

  if (offset == 0)
    {
      ... build snapshot ...
    }
  else
    {
       ... return a piece of the previously built snapshot ...
    }
}

Triggered with "(gdb) info os processes".

We've managed to get away with this so far, because we took the
assumption that GDB always reads the full object, and always
reads it sequencially starting at offset 0.  Another drawback with
this is the need to keep an in-memory snapshot of the object (the
static vars shown above).  We currently keep the snapshot in memory
until a new transfer of the same object starts.

I now notice the new TARGET_OBJECT_PROC implementation was not safe
against this issue.

If we assumed that GDB never transfers more than
one object at the same time (which is true today), we could make
the server discard any previous snapshot whenever it sees an
unrelated packet.  These workarounds don't sound like a good idea to
me for file access.

> > > [ I guess we could implement TARGET_OBJECT_PROC without a new packet type
> > > but implementing TARGET_OBJECT_PROC xfer in remote.c via remote_hostio_pread.
> > > This makes the assumption that the remote side always has a Linux-style /proc,
> > > however.  Not sure whether we should make that assumption ... ]
> > 
> > If the OS does has something else entirely, then the gdbarch method will
> > be aware, because it is the gdbarch method itself that retrieves
> > the data.  It may even use something completely different, not
> > based on filesystems at all.  Otherwise, we're back at making targets
> > fake a file system and proc interface they don't have, where we might
> > as well return some structured data.
> 
> Hmm, OK.  I agree.  So this option would be to:
> 
> - Define a new TARGET_OBJECT_FILE.  The "annex" is simply a full path name
>   of a file on the target system.
> 
> - Implement its xfer method for native targets, probably in inf-ptrace.c
>   (or maybe even as generic default in target.c), via native file I/O.

inf-child.c may be better than inf-ptrace.c.  target.c sounds fine too.
We'd probably want to make the methods be run on the default run target,
if no target is pushed.

> - Implement its xfer method for remote targets in remote.c, using the
>   hostio mechanism (no new packets required).
> 
> - Implement its xfer method for core files via a gdbarch callback allowing
>   the arch to synthesize contents of arbitrary files.
> 
> 
> Note that to fully implement "info proc", we also need to be able to
> read the link path names for files that happen to be symbolic links.
> For TARGET_OBJECT_PROC, I simply defined the target object that way;
> this doesn't really make sense for TARGET_OBJECT_FILE.  So we might
> want to add another target object type TARGET_OBJECT_SYMLINK that
> provides that capability.  Unfortunately, this does mean we need a
> new remote protocol packet, since hostio does not support readlink ...

That's unfortunate, though, it sounds like something generically useful
for other scenarios too.

> Pros of this method would be:
> 
> - New target objects are quite generic and well-defined.
> 
> - "info proc" now can go back to display info about arbitrary processes.
> 
> - No new remote protocol packets for TARGET_OBJECT_FILE.
> 
> 
> Cons of the method:
> 
> - Need new remote protocol packet for TARGET_OBJECT_SYMLINK after all.
> 
> - Synthesizing file contents for core files is a bit more awkward, since
>   you have to recognize particular /proc/PID/... file names.
> 
> 
> The alternative to TARGET_OBJECT_FILE/SYMLINK would be to provide a set
> of target_file_... accessor routines that map to native IO for native
> targets and hostio for remote targets, again with a gdbarch option to
> synthesize file contents from core files.

Right, that's what my "alternatively, wrap the hostio mechanism in a
ui-file (through open/read/write/close/... target methods perhaps), and
use that." comment aluded to.  Since you'd need to keep a reference
to an open handle to a file somewhere, I thought ui-file could be good
for that.  The core target could just use mem_fileopen() to return an
in-memory ui-file with the synthetic /proc/PID/... contents.  I guess
we'd need a new symlink ui-file type too.

> This would require the exact same set of remote protocol extensions
> as the above (i.e. a vFile:readlink or so), and allow the exact same
> set of capabilities; this is purely a question of what GDB-internal
> interface is preferable.

I lean torwards not using target objects for this.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-09 13:28                                 ` Pedro Alves
@ 2011-12-09 14:10                                   ` Pedro Alves
  0 siblings, 0 replies; 83+ messages in thread
From: Pedro Alves @ 2011-12-09 14:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ulrich Weigand, jan.kratochvil, sergiodj

On Friday 09 December 2011 12:56:41, Pedro Alves wrote:
> > The alternative to TARGET_OBJECT_FILE/SYMLINK would be to provide a set
> > of target_file_... accessor routines that map to native IO for native
> > targets and hostio for remote targets, again with a gdbarch option to
> > synthesize file contents from core files.
> 
> Right, that's what my "alternatively, wrap the hostio mechanism in a
> ui-file (through open/read/write/close/... target methods perhaps), and
> use that." comment aluded to.  Since you'd need to keep a reference
> to an open handle to a file somewhere, I thought ui-file could be good
> for that.  The core target could just use mem_fileopen() to return an
> in-memory ui-file with the synthetic /proc/PID/... contents.  I guess
> we'd need a new symlink ui-file type too.

Actually looking at the remote_bfd_iovec_open, remote_bfd_iovec_pread,
etc., an ui-file would probably be unnecessary and overkill.  The target
methods can just work on the file descriptor (as you were probably
thinking).  That'd mean the core target's implementation would
need to manage it's own little list of open file handles, though.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-07 20:14                               ` Ulrich Weigand
  2011-12-09 13:28                                 ` Pedro Alves
@ 2011-12-20 23:08                                 ` Ulrich Weigand
  2011-12-21 22:36                                   ` Jan Kratochvil
  2012-01-05 16:02                                   ` Pedro Alves
  1 sibling, 2 replies; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-20 23:08 UTC (permalink / raw)
  To: alves.ped; +Cc: gdb-patches, jan.kratochvil, sergiodj

I wrote:
> Pros of this method would be:
> 
> - New target objects are quite generic and well-defined.
> 
> - "info proc" now can go back to display info about arbitrary processes.
> 
> - No new remote protocol packets for TARGET_OBJECT_FILE.
> 
> 
> Cons of the method:
> 
> - Need new remote protocol packet for TARGET_OBJECT_SYMLINK after all.
> 
> - Synthesizing file contents for core files is a bit more awkward, since
>   you have to recognize particular /proc/PID/... file names.
> 
> 
> The alternative to TARGET_OBJECT_FILE/SYMLINK would be to provide a set
> of target_file_... accessor routines that map to native IO for native
> targets and hostio for remote targets, again with a gdbarch option to
> synthesize file contents from core files.

I actually completed an implementation of this (second) method, before
I noticed that it fundamentally does not work with the current remote
protocol, for one simple reason:  I cannot open /proc/PID/... because
I do not even know the PID to use.  With the remote target, the "PID"
used within GDB may have no relationship whatsoever to the actual PID
on a Linux remote target; in fact, it usually is the "magic" 42000 ...

While in some cases, the (a) remote PID may be encoded into the GDB
TID field, I cannot use this in -tdep code either, because when used
with the native target, the TID is never a PID/LWP.

Any suggestions?

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-20 23:08                                 ` Ulrich Weigand
@ 2011-12-21 22:36                                   ` Jan Kratochvil
  2011-12-22 16:15                                     ` Ulrich Weigand
  2012-01-05 16:02                                   ` Pedro Alves
  1 sibling, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2011-12-21 22:36 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: alves.ped, gdb-patches, sergiodj

On Tue, 20 Dec 2011 23:15:46 +0100, Ulrich Weigand wrote:
> protocol, for one simple reason:  I cannot open /proc/PID/... because
> I do not even know the PID to use.  With the remote target, the "PID"
> used within GDB may have no relationship whatsoever to the actual PID
> on a Linux remote target; in fact, it usually is the "magic" 42000 ...
> 
> While in some cases, the (a) remote PID may be encoded into the GDB
> TID field, I cannot use this in -tdep code either, because when used
> with the native target, the TID is never a PID/LWP.
> 
> Any suggestions?

It nicely proves the filenames should be abstracted by the target gdbserver.


Regards,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-21 22:36                                   ` Jan Kratochvil
@ 2011-12-22 16:15                                     ` Ulrich Weigand
  0 siblings, 0 replies; 83+ messages in thread
From: Ulrich Weigand @ 2011-12-22 16:15 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: alves.ped, gdb-patches, sergiodj

Jan Kratochvil wrote:
> On Tue, 20 Dec 2011 23:15:46 +0100, Ulrich Weigand wrote:
> > protocol, for one simple reason:  I cannot open /proc/PID/... because
> > I do not even know the PID to use.  With the remote target, the "PID"
> > used within GDB may have no relationship whatsoever to the actual PID
> > on a Linux remote target; in fact, it usually is the "magic" 42000 ...
> > 
> > While in some cases, the (a) remote PID may be encoded into the GDB
> > TID field, I cannot use this in -tdep code either, because when used
> > with the native target, the TID is never a PID/LWP.
> > 
> > Any suggestions?
> 
> It nicely proves the filenames should be abstracted by the target gdbserver.

Yes, I'd tend to agree this means it's back to the TARGET_OBJECT_PROC
approach ...   But let's give Pedro the chance to comment, since he was
the one who championed the generic target file based approach.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2011-12-20 23:08                                 ` Ulrich Weigand
  2011-12-21 22:36                                   ` Jan Kratochvil
@ 2012-01-05 16:02                                   ` Pedro Alves
  2012-01-05 18:03                                     ` Ulrich Weigand
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2012-01-05 16:02 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

On 12/20/2011 10:15 PM, Ulrich Weigand wrote:
> I wrote:
>> Pros of this method would be:
>>
>> - New target objects are quite generic and well-defined.
>>
>> - "info proc" now can go back to display info about arbitrary processes.
>>
>> - No new remote protocol packets for TARGET_OBJECT_FILE.
>>
>>
>> Cons of the method:
>>
>> - Need new remote protocol packet for TARGET_OBJECT_SYMLINK after all.
>>
>> - Synthesizing file contents for core files is a bit more awkward, since
>>    you have to recognize particular /proc/PID/... file names.
>>
>>
>> The alternative to TARGET_OBJECT_FILE/SYMLINK would be to provide a set
>> of target_file_... accessor routines that map to native IO for native
>> targets and hostio for remote targets, again with a gdbarch option to
>> synthesize file contents from core files.
>
> I actually completed an implementation of this (second) method, before
> I noticed that it fundamentally does not work with the current remote
> protocol, for one simple reason:  I cannot open /proc/PID/... because
> I do not even know the PID to use.  With the remote target, the "PID"
> used within GDB may have no relationship whatsoever to the actual PID
> on a Linux remote target; in fact, it usually is the "magic" 42000 ...

In extended-remote (w/ multiprocess extensions on), we do know the PID,
because the TID's are in the form pPID.TID.  With regular remote, we only
know the PID on "attach", because the user typed it, otherwise we fall back to
the magic 42000.  But why not simply fix this?  We can query the remote
end for the current process's ID, with target remote, and use that pid if
supported, otherwise fall back to the current magic 42000 use.   All the
options so far require new packets, so this doesn't seem to make it worse.
The tdep code in question is handling linux specific bits, so it can
bail out on the magic 42000 safely.  Another option, perhaps the cleanest,
is to start allowing the multiprocess thread id extensions with
plain "target remote".  GDB currently only sends "multiprocess+" qSupported
feature if connecting in extended-remote mode.  I can help and try this is
you'd like.

Not knowing the current remote process' PID seems like yet another
generic and unnecessary limitation on Linux targets.  E.g., in the I/T sets
series, I added a way to build sets with prefix letters, like 'i' for
inferiors, 't' for threads, 'a' for Ada tasks, and had planned to use 'p'
for processes.  To be useful with plain "target remote" against gdbserver,
the latter would require this change as well.

> While in some cases, the (a) remote PID may be encoded into the GDB
> TID field,I cannot use this in -tdep code either, because when used
> with the native target, the TID is never a PID/LWP.

Not sure what example you're referring to.  :-(

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 16:02                                   ` Pedro Alves
@ 2012-01-05 18:03                                     ` Ulrich Weigand
  2012-01-05 18:20                                       ` Pedro Alves
  2012-01-05 18:37                                       ` Mark Kettenis
  0 siblings, 2 replies; 83+ messages in thread
From: Ulrich Weigand @ 2012-01-05 18:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On 12/20/2011 10:15 PM, Ulrich Weigand wrote:
> > I actually completed an implementation of this (second) method, before
> > I noticed that it fundamentally does not work with the current remote
> > protocol, for one simple reason:  I cannot open /proc/PID/... because
> > I do not even know the PID to use.  With the remote target, the "PID"
> > used within GDB may have no relationship whatsoever to the actual PID
> > on a Linux remote target; in fact, it usually is the "magic" 42000 ...
> 
> In extended-remote (w/ multiprocess extensions on), we do know the PID,
> because the TID's are in the form pPID.TID.  With regular remote, we only
> know the PID on "attach", because the user typed it, otherwise we fall back to
> the magic 42000.  But why not simply fix this?  We can query the remote
> end for the current process's ID, with target remote, and use that pid if
> supported, otherwise fall back to the current magic 42000 use.   All the
> options so far require new packets, so this doesn't seem to make it worse.
> The tdep code in question is handling linux specific bits, so it can
> bail out on the magic 42000 safely.

I'm wondering: How can I distinguish the "magic 42000" from
a regular PID 42000 ?

> Another option, perhaps the cleanest,
> is to start allowing the multiprocess thread id extensions with
> plain "target remote".  GDB currently only sends "multiprocess+" qSupported
> feature if connecting in extended-remote mode.  I can help and try this is
> you'd like.

Yes, this does sound like an interesting approach.

> > While in some cases, the (a) remote PID may be encoded into the GDB
> > TID field,I cannot use this in -tdep code either, because when used
> > with the native target, the TID is never a PID/LWP.
> 
> Not sure what example you're referring to.  :-(

Well, GDB's "ptid_t" contains three fields: pid, lwp, and tid.  From what
I recall, these are used somewhat differently on different targets.

In particular, with Linux native targets, "pid" is what getpid () returns;
"lwp" is the Linux task ID -- which is equal to the pid for single-threaded
processes, and "tid" is the value of "pthread_t" for the thread.

Now, with the remote target, "pid" seems to be the magic 42000; "lwp" is
never used, and "tid" is used for the thread ID used with the remote
protocol -- and when using gdbserver, the latter is actually the LWP ID
 / Linux task ID.


What I was trying to say with the statement above is: if I knew the LWP
ID, I could use this to access /proc, since there is a /proc/... entry
for all LWP IDs as well as for the main PID.  And in fact, at least
for multi-threaded processes, I *do* know the LWP ID, since it is in fact
used as the TID field of the ptid_t with remote/gdbserver targets.

The problem is, with the native target, the TID field is used to hold
the "pthread_t" value, *not* the LWP ID.  Since -tdep code needs to
work with either target, I cannot really interpret that field in any
way ...                                                                                                                             


Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 18:03                                     ` Ulrich Weigand
@ 2012-01-05 18:20                                       ` Pedro Alves
  2012-01-05 19:54                                         ` Ulrich Weigand
  2012-01-05 18:37                                       ` Mark Kettenis
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2012-01-05 18:20 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

On 01/05/2012 06:02 PM, Ulrich Weigand wrote:
> Pedro Alves wrote:
>> On 12/20/2011 10:15 PM, Ulrich Weigand wrote:
>>> I actually completed an implementation of this (second) method, before
>>> I noticed that it fundamentally does not work with the current remote
>>> protocol, for one simple reason:  I cannot open /proc/PID/... because
>>> I do not even know the PID to use.  With the remote target, the "PID"
>>> used within GDB may have no relationship whatsoever to the actual PID
>>> on a Linux remote target; in fact, it usually is the "magic" 42000 ...
>>
>> In extended-remote (w/ multiprocess extensions on), we do know the PID,
>> because the TID's are in the form pPID.TID.  With regular remote, we only
>> know the PID on "attach", because the user typed it, otherwise we fall back to
>> the magic 42000.  But why not simply fix this?  We can query the remote
>> end for the current process's ID, with target remote, and use that pid if
>> supported, otherwise fall back to the current magic 42000 use.   All the
>> options so far require new packets, so this doesn't seem to make it worse.
>> The tdep code in question is handling linux specific bits, so it can
>> bail out on the magic 42000 safely.
>
> I'm wondering: How can I distinguish the "magic 42000" from
> a regular PID 42000 ?

AFAIK, there's no such thing as a 42000 PID; PIDs on Linux are limited
to 16-bit.

We could easily have an inferior->fake_pid_p boolean flag in
the inferior struct if we needed.

>
>> Another option, perhaps the cleanest,
>> is to start allowing the multiprocess thread id extensions with
>> plain "target remote".  GDB currently only sends "multiprocess+" qSupported
>> feature if connecting in extended-remote mode.  I can help and try this is
>> you'd like.
>
> Yes, this does sound like an interesting approach.

I'll give it a try if necessary, but with your idea below, it may not.

>>> While in some cases, the (a) remote PID may be encoded into the GDB
>>> TID field,I cannot use this in -tdep code either, because when used
>>> with the native target, the TID is never a PID/LWP.
>>
>> Not sure what example you're referring to.  :-(
>
> Well, GDB's "ptid_t" contains three fields: pid, lwp, and tid.  From what
> I recall, these are used somewhat differently on different targets.

> In particular, with Linux native targets, "pid" is what getpid () returns;
> "lwp" is the Linux task ID -- which is equal to the pid for single-threaded
> processes, and "tid" is the value of "pthread_t" for the thread.

Ah.  I see the confusion.  That's no longer the case for a couple years.
We only store the LWP id in the ptid.  The TID is always empty.  We don't need
the pthread_id, given Linux's 1:1 thread model.

> Now, with the remote target, "pid" seems to be the magic 42000; "lwp" is
> never used, and "tid" is used for the thread ID used with the remote
> protocol -- and when using gdbserver, the latter is actually the LWP ID
>   / Linux task ID.

Right.  So in reality, only ever one of the tid or the lwpid fields is
non-zero.  And the one that is non-zero is the LWP id we want.

> What I was trying to say with the statement above is: if I knew the LWP
> ID, I could use this to access /proc, since there is a /proc/... entry
> for all LWP IDs as well as for the main PID.  And in fact, at least
> for multi-threaded processes, I *do* know the LWP ID, since it is in fact
> used as the TID field of the ptid_t with remote/gdbserver targets.

That's a good point.

>
> The problem is, with the native target, the TID field is used to hold
> the "pthread_t" value, *not* the LWP ID.

We're good then, because that is not true on Linux anymore.
The TID field is not used for anything, and the LWP ID is in
the LWPID field.

(Actually back when we used to fill in the TID field with the pthread_t
value, we also put the LWP id in the lwpid field of the ptid, so if LWPID
was 0 and TID was not, the PTID must have been a remote one.)

> Since -tdep code needs to
> work with either target, I cannot really interpret that field in any
> way ...

>
>
> Bye,
> Ulrich

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 18:03                                     ` Ulrich Weigand
  2012-01-05 18:20                                       ` Pedro Alves
@ 2012-01-05 18:37                                       ` Mark Kettenis
  2012-01-05 19:35                                         ` Ulrich Weigand
  1 sibling, 1 reply; 83+ messages in thread
From: Mark Kettenis @ 2012-01-05 18:37 UTC (permalink / raw)
  To: uweigand; +Cc: alves.ped, gdb-patches, jan.kratochvil, sergiodj

> Date: Thu, 5 Jan 2012 19:02:35 +0100 (CET)
> From: "Ulrich Weigand" <uweigand@de.ibm.com>
> 
> I'm wondering: How can I distinguish the "magic 42000" from
> a regular PID 42000 ?

Traditionally on Unix, process IDs would wrap at 32767.  I believe
Linux still does this as well.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 18:37                                       ` Mark Kettenis
@ 2012-01-05 19:35                                         ` Ulrich Weigand
  0 siblings, 0 replies; 83+ messages in thread
From: Ulrich Weigand @ 2012-01-05 19:35 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: alves.ped, gdb-patches, jan.kratochvil, sergiodj

Mark Kettenis wrote:
> > Date: Thu, 5 Jan 2012 19:02:35 +0100 (CET)
> > From: "Ulrich Weigand" <uweigand@de.ibm.com>
> > 
> > I'm wondering: How can I distinguish the "magic 42000" from
> > a regular PID 42000 ?
> 
> Traditionally on Unix, process IDs would wrap at 32767.  I believe
> Linux still does this as well.

Ah, indeed.  But on Linux this is not a fixed limit any more,
but a configurable parameter (/proc/sys/kernel/pid_max) which
only still *defaults* to 32767.

So it could be easily possible to have Linux systems with
process IDs larger than 32767, it just needs the sysadmin
to change that default ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 18:20                                       ` Pedro Alves
@ 2012-01-05 19:54                                         ` Ulrich Weigand
  2012-01-06  6:41                                           ` Joel Brobecker
  2012-01-06 12:27                                           ` Pedro Alves
  0 siblings, 2 replies; 83+ messages in thread
From: Ulrich Weigand @ 2012-01-05 19:54 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On 01/05/2012 06:02 PM, Ulrich Weigand wrote:
> > I'm wondering: How can I distinguish the "magic 42000" from
> > a regular PID 42000 ?
> 
> AFAIK, there's no such thing as a 42000 PID; PIDs on Linux are limited
> to 16-bit.

See my reply to Mark; this is no longer true in general these days.
 
> > In particular, with Linux native targets, "pid" is what getpid () returns;
> > "lwp" is the Linux task ID -- which is equal to the pid for single-threaded
> > processes, and "tid" is the value of "pthread_t" for the thread.
> 
> Ah.  I see the confusion.  That's no longer the case for a couple years.
> We only store the LWP id in the ptid.  The TID is always empty.  We don't need
> the pthread_id, given Linux's 1:1 thread model.

Ah right, I missed that.

> > Now, with the remote target, "pid" seems to be the magic 42000; "lwp" is
> > never used, and "tid" is used for the thread ID used with the remote
> > protocol -- and when using gdbserver, the latter is actually the LWP ID
> >   / Linux task ID.
> 
> Right.  So in reality, only ever one of the tid or the lwpid fields is
> non-zero.  And the one that is non-zero is the LWP id we want.

Well, I guess one could implement some heuristics along those lines
that do indeed work with Linux native and gdbserver targets.
But this would still make a number of assumptions about how those fields
are used -- which may be true at the moment, but not guaranteed.

In particular, it seems to me that the remote protocol specification
considers TID values to be defined by the remote side; the host side
should only use them as identifiers without interpreting them.  While
gdbserver does use the LWPID here, I don't think it is guaranteed that
other implementations of the remote protocol do the same, even on
Linux targets (i.e. where linux-tdep files get used).

So all in all, this still looks a violation of abstraction layers
to me, which is the main reason why I advocated going back to the
TARGET_OBJECT_PROC approach ...


Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 19:54                                         ` Ulrich Weigand
@ 2012-01-06  6:41                                           ` Joel Brobecker
  2012-01-06 12:29                                             ` Pedro Alves
  2012-01-06 12:27                                           ` Pedro Alves
  1 sibling, 1 reply; 83+ messages in thread
From: Joel Brobecker @ 2012-01-06  6:41 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Pedro Alves, gdb-patches, jan.kratochvil, sergiodj

> > AFAIK, there's no such thing as a 42000 PID; PIDs on Linux are limited
> > to 16-bit.
> 
> See my reply to Mark; this is no longer true in general these days.

It wasn't true even before.  Other old systems such as mips-irix also
had 64bit PIDs, for instance, or Tru64.

-- 
Joel

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-05 19:54                                         ` Ulrich Weigand
  2012-01-06  6:41                                           ` Joel Brobecker
@ 2012-01-06 12:27                                           ` Pedro Alves
  2012-01-09 15:44                                             ` Ulrich Weigand
  1 sibling, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2012-01-06 12:27 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

On 01/05/2012 07:53 PM, Ulrich Weigand wrote:
> Pedro Alves wrote:
>> On 01/05/2012 06:02 PM, Ulrich Weigand wrote:
>>> I'm wondering: How can I distinguish the "magic 42000" from
>>> a regular PID 42000 ?
>>
>> AFAIK, there's no such thing as a 42000 PID; PIDs on Linux are limited
>> to 16-bit.
>
> See my reply to Mark; this is no longer true in general these days.

Thanks.  Always learning.  However, the problem was knowing when
42000 was the magic PID, or when it was a real PID.  That
should not be a problem, because it is GDB itself that comes up
with the 42000 magic number, not the server.  It's just a GDB
implementation detail.

>> Right.  So in reality, only ever one of the tid or the lwpid fields is
>> non-zero.  And the one that is non-zero is the LWP id we want.
>
> Well, I guess one could implement some heuristics along those lines
> that do indeed work with Linux native and gdbserver targets.
> But this would still make a number of assumptions about how those fields
> are used -- which may be true at the moment, but not guaranteed.
>
> In particular, it seems to me that the remote protocol specification
> considers TID values to be defined by the remote side; the host side
> should only use them as identifiers without interpreting them.

Yes, that is true in general.

> While gdbserver does use the LWPID here, I don't think it is guaranteed that
> other implementations of the remote protocol do the same, even on
> Linux targets (i.e. where linux-tdep files get used).

... however, let's revisit the problem with a fresh start.

We have a command "info proc FOO PID", that accepts any target process ID,
whose description is:

  (gdb) help info proc
  Show /proc process information about any running process.
  Specify any process id, or use the program being debugged by default.

Let's ignore the "or use the program being debugged by default" part
for now; it is a (big) convenience, and a separate problem, one of mapping
the program being debugged to a process id.  (The dropping of the
support for specifying any process id in the proposed implementations
seems more like accommodating the implementation, so let's step back on
that too.)

Now, we want to make this work on remote targets.  For several reasons
I've stated, I think this is best done with converting the always-host
open/read/close's into remote target filesystem operations.  To recap:

  - target objects aren't ideal for the case of reading files out of
    /proc for the case of reading them from random processes, not being
    debugged, that are currently running, because on the server side, you
    need to open/read/close the file descriptor at every partial transfer,
    which leads itself to corrupt transfers if the file changes between
    partial transfers, or, you need to cache the whole object (as we
    presently do for xml objects).  The latter has the downside of
    needing to hold on to the object in memory on the server side, and
    to assume GDB always reads the object starting from offset 0.  IMO,
    that's not a good assumption for binary objects.

  - A natural solution, is, IMO, realize we're already assuming a /proc
    target on the client (gdb) side, so the client might as well read
    the /proc files directly itself.

After this, we're now left with the "or use the program being debugged
by default" problem to solve.  This has a use in more scenarios, so it's
useful to state it as a problem in its own right.  Off-hand examples are,
I/T sets `p' prefix idea, and even remote core generation, so you can
write the correct PID on the core file.

So this sub-problem can be simply specified as:

   Given a gdb inferior or thread, return it's target process id.

Now, we can come up with a new method to retrieve that info from
the server.  However, all the Linux targets I know about that have
/proc contents access (gdbserver), have a 1:1 mapping in the RSP
between RSP process, and target process, so we might as well start
out with defaulting to assume that, and add such a mechanism when
we find a need for it.  IMO.

 > So all in all, this still looks a violation of abstraction layers
 > to me,

So I see this as two distinct, but related problems.  And when I look
at the /proc retrieval part alone, I favor the remote filesystem
access, as the most natural way to transparently make the command
work with remote targets.  And for cores too, as you yourself
mentioned, the kernel can put /proc contents in cores, and, I could
imagine taking a snapshot of /proc for the whole process tree (either
above a given process (children, siblings, etc.), or starting at
PID 1, and storing that in, or along the core, to be something useful.

 > which is the main reason why I advocated going back to the
 > TARGET_OBJECT_PROC approach ...

If you're still not convinced, and others don't support my view,
than I will step back and won't block your going forward with that.
However, what did you think of my earlier comments regarding
splitting that into separate objects?

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-06  6:41                                           ` Joel Brobecker
@ 2012-01-06 12:29                                             ` Pedro Alves
  0 siblings, 0 replies; 83+ messages in thread
From: Pedro Alves @ 2012-01-06 12:29 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Ulrich Weigand, gdb-patches, jan.kratochvil, sergiodj

On 01/06/2012 06:41 AM, Joel Brobecker wrote:
>>> AFAIK, there's no such thing as a 42000 PID; PIDs on Linux are limited
>>> to 16-bit.
>>
>> See my reply to Mark; this is no longer true in general these days.
>
> It wasn't true even before.  Other old systems such as mips-irix also
> had 64bit PIDs, for instance, or Tru64.

AFAIK, neither Irix nor Tru64 use the Linux kernel :-)  If we step out
of Linux, then my assertion above would be false even for Windows.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-06 12:27                                           ` Pedro Alves
@ 2012-01-09 15:44                                             ` Ulrich Weigand
  2012-01-11 16:38                                               ` Pedro Alves
  0 siblings, 1 reply; 83+ messages in thread
From: Ulrich Weigand @ 2012-01-09 15:44 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On 01/05/2012 07:53 PM, Ulrich Weigand wrote:
> > Well, I guess one could implement some heuristics along those lines
> > that do indeed work with Linux native and gdbserver targets.
> > But this would still make a number of assumptions about how those fields
> > are used -- which may be true at the moment, but not guaranteed.
> >
> > In particular, it seems to me that the remote protocol specification
> > considers TID values to be defined by the remote side; the host side
> > should only use them as identifiers without interpreting them.
> 
> Yes, that is true in general.
> 
> > While gdbserver does use the LWPID here, I don't think it is guaranteed that
> > other implementations of the remote protocol do the same, even on
> > Linux targets (i.e. where linux-tdep files get used).
> 
> ... however, let's revisit the problem with a fresh start.
> 
> We have a command "info proc FOO PID", that accepts any target process ID,
> whose description is:
> 
>   (gdb) help info proc
>   Show /proc process information about any running process.
>   Specify any process id, or use the program being debugged by default.
> 
> Let's ignore the "or use the program being debugged by default" part
> for now; it is a (big) convenience, and a separate problem, one of mapping
> the program being debugged to a process id.  (The dropping of the
> support for specifying any process id in the proposed implementations
> seems more like accommodating the implementation, so let's step back on
> that too.)

It seems to me we're getting to the core of the problem here.  For the
existing "info proc" command, it indeed makes sense to talk about
"process IDs", *because* the command is specific to a (native) target
that supports processes and uses process IDs.

Except for this, common GDB user interface commands do not currently
refer to "process IDs"; while GDB obviously used "ptid_t" internally,
it is *interpreted* only by target code, common code at most uses it
for comparions (is this the same process as another one).

[ The one obvious exception is the "attach" command which also takes
a process ID.  However, this is arguably also a target-specific command,
in that the generic implementation quickly calls through to target code
that implements the operation, starting with *parsing the argument*. ]

Instead of refering to process IDs, GDB commands usually operate on
the "current inferior", or else take GDB inferior (or thread) IDs as
argument, which have no direct connection to the underlying OS
process IDs.

It seems to me this was a deliberate decision to try and isolate the
common GDB code and user interfaces from OS implementation details:
GDB is supposed to work just the same on targets where there are no
processes, or where they are identified by different means that just
an integer ID.


Now, given the "anomaly" of the "info proc" command as is, I guess
there's two ways to look at how to move forward:

- We could say the anomaly was a mistake that we want to get rid of.
  In this view, it naturally follows that we remove the PID argument
  option and have the command operate on the "current inferior" as
  all other commands.  This also makes an underlying interface that
  would retrieve proc file content of the current inferior natural.
  (This is what my patch set has implemented.)

- We say instead that, yes, we *want* OS PIDs to be used as first-
  class user interface elements.  But this means to me that we
  need to more generally make OS PIDs present in GDB common code
  so that common code is at least able to associate its internal
  notions of "inferior" with those IDs.  At a minimum, this would
  imply we no longer consider "ptid_t" values to be opaque to
  GDB common code, but rather enforce that they agree with user-
  visible OS PID values.

Now, I'm not necessarily opposed to the second approach, I'm just
not sure I see all the consequences ...   At a minimum, the use
of the "magic 42000" becomes problematic if there is any chance
the ptid_t gets exposed to the user at any point.

> So this sub-problem can be simply specified as:
> 
>    Given a gdb inferior or thread, return it's target process id.
> 
> Now, we can come up with a new method to retrieve that info from
> the server.  However, all the Linux targets I know about that have
> /proc contents access (gdbserver), have a 1:1 mapping in the RSP
> between RSP process, and target process, so we might as well start
> out with defaulting to assume that, and add such a mechanism when
> we find a need for it.  IMO.

I don't quite understand what you mean here.  Could you elaborate
how you propose to implement this routine "return the target process
ID of a given GDB inferior/thread" without remote interface changes?
This was exactly the "magic 42000" problem I was running into ...

>  > So all in all, this still looks a violation of abstraction layers
>  > to me,
> 
> So I see this as two distinct, but related problems.  And when I look
> at the /proc retrieval part alone, I favor the remote filesystem
> access, as the most natural way to transparently make the command
> work with remote targets.  And for cores too, as you yourself
> mentioned, the kernel can put /proc contents in cores, and, I could
> imagine taking a snapshot of /proc for the whole process tree (either
> above a given process (children, siblings, etc.), or starting at
> PID 1, and storing that in, or along the core, to be something useful.

I could imaging a core file of a process containing snapshots of /proc
files *for that process*.  It would seem rather odd to me to have /proc
files of *other* processes as part of a core file.  But that's certainly
a side discussion ...

>  > which is the main reason why I advocated going back to the
>  > TARGET_OBJECT_PROC approach ...
> 
> If you're still not convinced, and others don't support my view,
> than I will step back and won't block your going forward with that.
> However, what did you think of my earlier comments regarding
> splitting that into separate objects?

I must admit I don't see what the benefit of this is supposed to be.
This seems to me to be the exact use case that "annex" is there to
cover: a bunch of information with related content semantics, which
are all accessed the same way, and the exact set is somewhat dynamic.

Not using the annex would mean defining a whole bunch of new packet
types, duplicated boilerplate code in GDB and gdbserver to hook them
up, and then still the drawback that every new /proc file that may
come up in the future will require extra code (including new gdbserver-side
code!) to support.  And for all those drawbacks, I don't see any single
benefit ...  Maybe you can elaborate?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-09 15:44                                             ` Ulrich Weigand
@ 2012-01-11 16:38                                               ` Pedro Alves
  2012-01-11 18:32                                                 ` Ulrich Weigand
  0 siblings, 1 reply; 83+ messages in thread
From: Pedro Alves @ 2012-01-11 16:38 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches, jan.kratochvil, sergiodj

[-- Attachment #1: Type: text/plain, Size: 8087 bytes --]

On 01/09/2012 03:43 PM, Ulrich Weigand wrote:
> Pedro Alves wrote:
>> On 01/05/2012 07:53 PM, Ulrich Weigand wrote:
>>> Well, I guess one could implement some heuristics along those lines
>>> that do indeed work with Linux native and gdbserver targets.
>>> But this would still make a number of assumptions about how those fields
>>> are used -- which may be true at the moment, but not guaranteed.
>>>
>>> In particular, it seems to me that the remote protocol specification
>>> considers TID values to be defined by the remote side; the host side
>>> should only use them as identifiers without interpreting them.
>>
>> Yes, that is true in general.
>>
>>> While gdbserver does use the LWPID here, I don't think it is guaranteed that
>>> other implementations of the remote protocol do the same, even on
>>> Linux targets (i.e. where linux-tdep files get used).
>>
>> ... however, let's revisit the problem with a fresh start.
>>
>> We have a command "info proc FOO PID", that accepts any target process ID,
>> whose description is:
>>
>>   (gdb) help info proc
>>   Show /proc process information about any running process.
>>   Specify any process id, or use the program being debugged by default.
>>
>> Let's ignore the "or use the program being debugged by default" part
>> for now; it is a (big) convenience, and a separate problem, one of mapping
>> the program being debugged to a process id.  (The dropping of the
>> support for specifying any process id in the proposed implementations
>> seems more like accommodating the implementation, so let's step back on
>> that too.)
> 
> It seems to me we're getting to the core of the problem here.  For the
> existing "info proc" command, it indeed makes sense to talk about
> "process IDs", *because* the command is specific to a (native) target
> that supports processes and uses process IDs.
> 
> Except for this, common GDB user interface commands do not currently
> refer to "process IDs"; while GDB obviously used "ptid_t" internally,
> it is *interpreted* only by target code, common code at most uses it
> for comparions (is this the same process as another one).
> 
> [ The one obvious exception is the "attach" command which also takes
> a process ID.  However, this is arguably also a target-specific command,
> in that the generic implementation quickly calls through to target code
> that implements the operation, starting with *parsing the argument*. ]
> 
> Instead of refering to process IDs, GDB commands usually operate on
> the "current inferior", or else take GDB inferior (or thread) IDs as
> argument, which have no direct connection to the underlying OS
> process IDs.
> 
> It seems to me this was a deliberate decision to try and isolate the
> common GDB code and user interfaces from OS implementation details:
> GDB is supposed to work just the same on targets where there are no
> processes, or where they are identified by different means that just
> an integer ID.
> 
> 
> Now, given the "anomaly" of the "info proc" command as is, I guess
> there's two ways to look at how to move forward:
> 
> - We could say the anomaly was a mistake that we want to get rid of.
>   In this view, it naturally follows that we remove the PID argument
>   option and have the command operate on the "current inferior" as
>   all other commands.  This also makes an underlying interface that
>   would retrieve proc file content of the current inferior natural.
>   (This is what my patch set has implemented.)
> 
> - We say instead that, yes, we *want* OS PIDs to be used as first-
>   class user interface elements.  But this means to me that we
>   need to more generally make OS PIDs present in GDB common code
>   so that common code is at least able to associate its internal
>   notions of "inferior" with those IDs.  At a minimum, this would
>   imply we no longer consider "ptid_t" values to be opaque to
>   GDB common code, but rather enforce that they agree with user-
>   visible OS PID values.

Note that I'm not talking about the notion of a "process id" escape
escape to common/core code, but only to the linux gdbarch/osabi
specific bits; or other code that can deal with it, guarded by
"is there a notion of a process id on this target.

> Now, I'm not necessarily opposed to the second approach, I'm just
> not sure I see all the consequences ...   At a minimum, the use
> of the "magic 42000" becomes problematic if there is any chance
> the ptid_t gets exposed to the user at any point.
> 
>> So this sub-problem can be simply specified as:
>>
>>    Given a gdb inferior or thread, return it's target process id.
>>
>> Now, we can come up with a new method to retrieve that info from
>> the server.  However, all the Linux targets I know about that have
>> /proc contents access (gdbserver), have a 1:1 mapping in the RSP
>> between RSP process, and target process, so we might as well start
>> out with defaulting to assume that, and add such a mechanism when
>> we find a need for it.  IMO.
> 
> I don't quite understand what you mean here.  Could you elaborate
> how you propose to implement this routine "return the target process
> ID of a given GDB inferior/thread" without remote interface changes?
> This was exactly the "magic 42000" problem I was running into ...

As mentioned before, by broadcasting support for multi-process extensions
even with "target remote" (but don't allow debugging multiple processes),
and defaulting to assume a 1:1 mapping between target process id
and RSP process id, until some target needs to do something else, at
which point we define a new packet.

I've spent a bit today prototyping /proc access this way the way
I was imagining it.  See the attached patch series.  This is far from
complete.  It's just enough to get something working.

> 
>>  > So all in all, this still looks a violation of abstraction layers
>>  > to me,
>>
>> So I see this as two distinct, but related problems.  And when I look
>> at the /proc retrieval part alone, I favor the remote filesystem
>> access, as the most natural way to transparently make the command
>> work with remote targets.  And for cores too, as you yourself
>> mentioned, the kernel can put /proc contents in cores, and, I could
>> imagine taking a snapshot of /proc for the whole process tree (either
>> above a given process (children, siblings, etc.), or starting at
>> PID 1, and storing that in, or along the core, to be something useful.
> 
> I could imaging a core file of a process containing snapshots of /proc
> files *for that process*.  It would seem rather odd to me to have /proc
> files of *other* processes as part of a core file.  But that's certainly
> a side discussion ...
> 
>>  > which is the main reason why I advocated going back to the
>>  > TARGET_OBJECT_PROC approach ...
>>
>> If you're still not convinced, and others don't support my view,
>> than I will step back and won't block your going forward with that.
>> However, what did you think of my earlier comments regarding
>> splitting that into separate objects?
> 
> I must admit I don't see what the benefit of this is supposed to be.
> This seems to me to be the exact use case that "annex" is there to
> cover: a bunch of information with related content semantics, which
> are all accessed the same way, and the exact set is somewhat dynamic.
> Not using the annex would mean defining a whole bunch of new packet
> types, duplicated boilerplate code in GDB and gdbserver to hook them
> up, and then still the drawback that every new /proc file that may
> come up in the future will require extra code (including new gdbserver-side
> code!) to support.  And for all those drawbacks, I don't see any single
> benefit ...  Maybe you can elaborate?

- Decoupling of the objects in question from a "/proc" idea, so they
can be more generally used in other scenarios, like e.g., a remote
protocol implementation of target_pid_to_str (TARGET_OBJECT_PROC/exe).
- Let GDB have a finer grained idea of what subset of /proc-ish objects
are supported upfront (through qSupported), without any new mechanism.

> 
> Bye,
> Ulrich
> 

[-- Attachment #2: 01-target_fileio.diff --]
[-- Type: text/x-patch, Size: 5080 bytes --]

Expose the fileio methods through the target vector.

From: Pedro Alves <palves@redhat.com>


---
 gdb/remote.c |    6 ++++++
 gdb/target.c |   25 +++++++++++++++++++++++++
 gdb/target.h |   47 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index 60d7ecd..7542882 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -10684,6 +10684,12 @@ Specify the serial device it is connected to\n\
   remote_ops.to_static_tracepoint_markers_by_strid
     = remote_static_tracepoint_markers_by_strid;
   remote_ops.to_traceframe_info = remote_traceframe_info;
+
+  remote_ops.to_file_open = remote_hostio_open;
+  remote_ops.to_file_pwrite = remote_hostio_pwrite;
+  remote_ops.to_file_pread = remote_hostio_pread;
+  remote_ops.to_file_close = remote_hostio_close;
+  remote_ops.to_file_unlink = remote_hostio_unlink;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
diff --git a/gdb/target.c b/gdb/target.c
index 9aaa0ea..74238a5 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -697,6 +697,13 @@ update_current_target (void)
       INHERIT (to_static_tracepoint_marker_at, t);
       INHERIT (to_static_tracepoint_markers_by_strid, t);
       INHERIT (to_traceframe_info, t);
+
+      INHERIT (to_file_open, t);
+      INHERIT (to_file_pwrite, t);
+      INHERIT (to_file_pread, t);
+      INHERIT (to_file_close, t);
+      INHERIT (to_file_unlink, t);
+
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -926,6 +933,24 @@ update_current_target (void)
 	    tcomplain);
   de_fault (to_execution_direction, default_execution_direction);
 
+  de_fault (to_file_open,
+	    (int (*) (const char *, int, int, int *))
+	    tcomplain);
+  de_fault (to_file_pwrite,
+	    (int (*) (int, const gdb_byte *, int,
+		      ULONGEST, int *))
+	    tcomplain);
+  de_fault (to_file_pread,
+	    (int (*) (int, gdb_byte *, int,
+		      ULONGEST, int *))
+	    tcomplain);
+  de_fault (to_file_close,
+	    (int (*) (int, int *))
+	    tcomplain);
+  de_fault (to_file_unlink,
+	    (int (*) (const char *, int *))
+	    tcomplain);
+
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
diff --git a/gdb/target.h b/gdb/target.h
index 7d0bed1..96176a5 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -795,6 +795,32 @@ struct target_ops
        re-fetching when necessary.  */
     struct traceframe_info *(*to_traceframe_info) (void);
 
+    /* Open FILENAME on the target, using FLAGS and MODE.  Return a
+       target file descriptor, or -1 if an error occurs (and set
+       *TARGET_ERRNO).  */
+    int (*to_file_open) (const char *filename, int flags, int mode,
+		      int *target_errno);
+
+    /* Write up to LEN bytes from WRITE_BUF to FD on the target.
+       Return the number of bytes written, or -1 if an error occurs
+       (and set *TARGET_ERRNO).  */
+    int (*to_file_pwrite) (int fd, const gdb_byte *write_buf, int len,
+			ULONGEST offset, int *target_errno);
+
+    /* Read up to LEN bytes FD on the target into READ_BUF.  Return
+       the number of bytes read, or -1 if an error occurs (and set
+       *TARGET_ERRNO).  */
+    int (*to_file_pread) (int fd, gdb_byte *read_buf, int len,
+		       ULONGEST offset, int *target_errno);
+
+    /* Close FD on the target.  Return 0, or -1 if an error occurs
+       (and set *TARGET_ERRNO).  */
+    int (*to_file_close) (int fd, int *target_errno);
+
+    /* Unlink FILENAME on the target.  Return 0, or -1 if an error
+       occurs (and set *TARGET_ERRNO).  */
+    int (*to_file_unlink) (const char *filename, int *target_errno);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1493,7 +1519,6 @@ extern int target_search_memory (CORE_ADDR start_addr,
 
 #define target_trace_init() \
   (*current_target.to_trace_init) ()
-
 #define target_download_tracepoint(t) \
   (*current_target.to_download_tracepoint) (t)
 
@@ -1744,6 +1769,26 @@ extern int may_stop;
 
 extern void update_target_permissions (void);
 
+/* See to_file_open for description.  */
+#define target_file_open(filename, flags, mode, target_errno)		\
+  (*current_target.to_file_open) (filename, flags, mode, target_errno)
+
+/* See to_file_pwrite for description.  */
+#define target_file_pwrite(fd, write_buf, len, offset, target_errno)	\
+  (*current_target.to_file_pwrite) (fd, write_buf, len, offset, target_errno)
+
+/* See to_file_pread for description.  */
+#define target_file_pread(fd, read_buf, len, offset, target_errno)	\
+  (*current_target.to_file_pread) (fd, read_buf, len, offset, target_errno)
+
+/* See to_file_close for description.  */
+#define target_file_close(fd, target_errno)		\
+  (*current_target.to_file_close) (fd, target_errno)
+
+/* See to_file_unlink for description.  */
+#define target_file_unlink(filename, target_errno)		\
+  (*current_target.to_file_close) (filename, target_errno)
+
 \f
 /* Imported from machine dependent code.  */
 

[-- Attachment #3: 02-proc_access_target.diff --]
[-- Type: text/x-patch, Size: 7502 bytes --]

Adjust linux's "info proc" command to read the /proc files from the target.

From: Pedro Alves <palves@redhat.com>

Obviously not a complete patch.  The command' implementation would
need to move behind a gdbarch callback, and only one /proc file access
has been adjusted.
---
 gdb/linux-nat.c |  203 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 195 insertions(+), 8 deletions(-)

diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index f6b36a2..d333c44 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4830,13 +4830,190 @@ enum info_proc_what
     IP_ALL
   };
 
+#include "gdb/fileio.h"
+
+static int
+fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
+{
+  int open_flags = 0;
+
+  if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
+    return -1;
+
+  if (fileio_open_flags & FILEIO_O_CREAT)
+    open_flags |= O_CREAT;
+  if (fileio_open_flags & FILEIO_O_EXCL)
+    open_flags |= O_EXCL;
+  if (fileio_open_flags & FILEIO_O_TRUNC)
+    open_flags |= O_TRUNC;
+  if (fileio_open_flags & FILEIO_O_APPEND)
+    open_flags |= O_APPEND;
+  if (fileio_open_flags & FILEIO_O_RDONLY)
+    open_flags |= O_RDONLY;
+  if (fileio_open_flags & FILEIO_O_WRONLY)
+    open_flags |= O_WRONLY;
+  if (fileio_open_flags & FILEIO_O_RDWR)
+    open_flags |= O_RDWR;
+/* On systems supporting binary and text mode, always open files in
+   binary mode. */
+#ifdef O_BINARY
+  open_flags |= O_BINARY;
+#endif
+
+  *open_flags_p = open_flags;
+  return 0;
+}
+
+static int
+errno_to_fileio_error (int error)
+{
+  switch (error)
+    {
+    case EPERM:
+      return FILEIO_EPERM;
+    case ENOENT:
+      return FILEIO_ENOENT;
+    case EINTR:
+      return FILEIO_EINTR;
+    case EIO:
+      return FILEIO_EIO;
+    case EBADF:
+      return FILEIO_EBADF;
+    case EACCES:
+      return FILEIO_EACCES;
+    case EFAULT:
+      return FILEIO_EFAULT;
+    case EBUSY:
+      return FILEIO_EBUSY;
+    case EEXIST:
+      return FILEIO_EEXIST;
+    case ENODEV:
+      return FILEIO_ENODEV;
+    case ENOTDIR:
+      return FILEIO_ENOTDIR;
+    case EISDIR:
+      return FILEIO_EISDIR;
+    case EINVAL:
+      return FILEIO_EINVAL;
+    case ENFILE:
+      return FILEIO_ENFILE;
+    case EMFILE:
+      return FILEIO_EMFILE;
+    case EFBIG:
+      return FILEIO_EFBIG;
+    case ENOSPC:
+      return FILEIO_ENOSPC;
+    case ESPIPE:
+      return FILEIO_ESPIPE;
+    case EROFS:
+      return FILEIO_EROFS;
+    case ENOSYS:
+      return FILEIO_ENOSYS;
+    case ENAMETOOLONG:
+      return FILEIO_ENAMETOOLONG;
+    }
+
+  return FILEIO_EUNKNOWN;
+}
+
+static int
+linux_nat_file_open (const char *filename, int flags, int mode,
+		    int *target_errno)
+{
+  int nat_flags;
+  int fd;
+
+  if (fileio_open_flags_to_host (flags, &nat_flags) == -1)
+    {
+      *target_errno = FILEIO_EINVAL;
+      return -1;
+    }
+
+  /* We do not need to convert MODE, since the fileio protocol uses
+     the standard values.  */
+  fd = open (filename, nat_flags, mode);
+  if (fd == -1)
+    *target_errno = errno_to_fileio_error (errno);
+  return fd;
+}
+
+static int
+linux_nat_file_pwrite (int fd, const gdb_byte *write_buf, int len,
+		      ULONGEST offset, int *target_errno)
+{
+  int ret;
+
+#ifdef HAVE_PWRITE
+  ret = pwrite (fd, write_buf, len, offset);
+#else
+  ret = lseek (fd, offset, SEEK_SET);
+  if (ret != -1)
+    ret = write (fd, write_buf, len);
+#endif
+
+  if (ret == -1)
+    *target_errno = errno_to_fileio_error (errno);
+  return ret;
+}
+
+static int
+linux_nat_file_pread (int fd, gdb_byte *read_buf, int len,
+		     ULONGEST offset, int *target_errno)
+{
+  int ret;
+
+#ifdef HAVE_PREAD
+  ret = pread (fd, read_buf, len, offset);
+#else
+  ret = lseek (fd, offset, SEEK_SET);
+  if (ret != -1)
+    ret = read (fd, read_buf, len);
+#endif
+
+  if (ret == -1)
+    *target_errno = errno_to_fileio_error (errno);
+
+  return ret;
+}
+
+static int
+linux_nat_file_close (int fd, int *target_errno)
+{
+  int ret;
+
+  ret = close (fd);
+  if (ret == -1)
+    *target_errno = errno_to_fileio_error (errno);
+
+  return ret;
+}
+
+static void
+do_target_file_close (void *arg)
+{
+  int fd = *(int *) arg;
+  int target_errno;
+
+  target_file_close (fd, &target_errno);
+  xfree (arg);
+}
+
+static struct cleanup *
+make_cleanup_target_file_close (int fd)
+{
+  int *fdp = XNEW (int);
+
+  *fdp = fd;
+  return make_cleanup (do_target_file_close, fdp);
+}
+
 static void
 linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
   long pid = PIDGET (inferior_ptid);
-  FILE *procfile;
+  int procfile;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
   int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
@@ -4846,6 +5023,7 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
   int status_f = (what == IP_STATUS || what == IP_ALL);
   int stat_f = (what == IP_STAT || what == IP_ALL);
   struct stat dummy;
+  int target_errno;
 
   if (args && isdigit (args[0]))
     pid = strtoul (args, &args, 10);
@@ -4857,19 +5035,17 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
   if (pid == 0)
     error (_("No current process: you must name one."));
 
-  sprintf (fname1, "/proc/%ld", pid);
-  if (stat (fname1, &dummy) != 0)
-    error (_("No /proc directory: '%s'"), fname1);
-
   printf_filtered (_("process %ld\n"), pid);
   if (cmdline_f)
     {
       sprintf (fname1, "/proc/%ld/cmdline", pid);
-      if ((procfile = fopen (fname1, "r")) != NULL)
+      if ((procfile = target_file_open (fname1, FILEIO_O_RDONLY,
+					0, &target_errno)) != -1)
 	{
-	  struct cleanup *cleanup = make_cleanup_fclose (procfile);
+	  struct cleanup *cleanup = make_cleanup_target_file_close (procfile);
 
-          if (fgets (buffer, sizeof (buffer), procfile))
+          if (target_file_pread (procfile, buffer, sizeof (buffer),
+				 0, &target_errno) != -1)
             printf_filtered ("cmdline = '%s'\n", buffer);
           else
             warning (_("unable to read '%s'"), fname1);
@@ -4898,6 +5074,8 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
     }
   if (mappings_f)
     {
+      FILE *procfile;
+
       sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
 	{
@@ -4960,6 +5138,8 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
     }
   if (status_f)
     {
+      FILE *procfile;
+
       sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
 	{
@@ -4974,6 +5154,8 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
     }
   if (stat_f)
     {
+      FILE *procfile;
+
       sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
 	{
@@ -5880,6 +6062,11 @@ linux_nat_add_target (struct target_ops *t)
 
   t->to_core_of_thread = linux_nat_core_of_thread;
 
+  t->to_file_open = linux_nat_file_open;
+  t->to_file_pwrite = linux_nat_file_pwrite;
+  t->to_file_pread = linux_nat_file_pread;
+  t->to_file_close = linux_nat_file_close;
+
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable

[-- Attachment #4: 03-process_id.diff --]
[-- Type: text/x-patch, Size: 4864 bytes --]

Record in `struct inferior' whether the target process id we have has been faked by GDB or not.

From: Pedro Alves <palves@redhat.com>


---
 gdb/inferior.c  |    1 +
 gdb/inferior.h  |    2 ++
 gdb/linux-nat.c |   18 ++++++++++++++----
 gdb/remote.c    |   42 ++++++++++++++++++++++++++++++++----------
 4 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/gdb/inferior.c b/gdb/inferior.c
index 65948c4..4df8c77 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -276,6 +276,7 @@ exit_inferior_1 (struct inferior *inftoex, int silent)
   observer_notify_inferior_exit (inf);
 
   inf->pid = 0;
+  inf->fake_pid_p = 0;
   if (inf->vfork_parent != NULL)
     {
       inf->vfork_parent->vfork_child = NULL;
diff --git a/gdb/inferior.h b/gdb/inferior.h
index f05789f..7857cbf 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -421,6 +421,8 @@ struct inferior
   /* Actual target inferior id, usually, a process id.  This matches
      the ptid_t.pid member of threads of this inferior.  */
   int pid;
+  /* True if the PID was actually faked by GDB.  */
+  int fake_pid_p;
 
   /* State of GDB control of inferior process execution.
      See `struct inferior_control_state'.  */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index d333c44..17236ec 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -5012,7 +5012,8 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
-  long pid = PIDGET (inferior_ptid);
+  long pid = 0;
+  int explicit_pid = 0;
   int procfile;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
@@ -5026,14 +5027,23 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
   int target_errno;
 
   if (args && isdigit (args[0]))
-    pid = strtoul (args, &args, 10);
+    {
+      pid = strtoul (args, &args, 10);
+      explicit_pid = 1;
+    }
 
   args = skip_spaces (args);
   if (args && args[0])
     error (_("Too many parameters: %s"), args);
 
-  if (pid == 0)
-    error (_("No current process: you must name one."));
+  if (!explicit_pid)
+    {
+      if (!target_has_execution)
+	error (_("No current process: you must name one."));
+      if (current_inferior ()->fake_pid_p)
+	error (_("Can't determine the current process's PID: you must name one."));
+      pid = ptid_get_pid (inferior_ptid);
+    }
 
   printf_filtered (_("process %ld\n"), pid);
   if (cmdline_f)
diff --git a/gdb/remote.c b/gdb/remote.c
index 7542882..c5c9481 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -3253,6 +3253,10 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
 
   if (!non_stop)
     {
+      ptid_t ptid;
+      int fake_pid_p = 0;
+      struct inferior *inf;
+
       if (rs->buf[0] == 'W' || rs->buf[0] == 'X')
 	{
 	  if (!extended_p)
@@ -3272,19 +3276,37 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
       /* Let the stub know that we want it to return the thread.  */
       set_continue_thread (minus_one_ptid);
 
-      /* Without this, some commands which require an active target
-	 (such as kill) won't work.  This variable serves (at least)
-	 double duty as both the pid of the target process (if it has
-	 such), and as a flag indicating that a target is active.
-	 These functions should be split out into seperate variables,
-	 especially since GDB will someday have a notion of debugging
-	 several processes.  */
-      inferior_ptid = magic_null_ptid;
+      inferior_ptid = minus_one_ptid;
 
       /* Now, if we have thread information, update inferior_ptid.  */
-      inferior_ptid = remote_current_thread (inferior_ptid);
+      ptid = remote_current_thread (inferior_ptid);
+      if (!ptid_equal (ptid, minus_one_ptid))
+	{
+	  if (ptid_get_pid (ptid) == -1)
+	    {
+	      ptid = ptid_build (ptid_get_pid (magic_null_ptid),
+				 ptid_get_lwp (ptid),
+				 ptid_get_tid (ptid));
+	      fake_pid_p = 1;
+	    }
+
+	  inferior_ptid = ptid;
+	}
+      else
+	{
+	  /* Without this, some commands which require an active
+	     target (such as kill) won't work.  This variable serves
+	     (at least) double duty as both the pid of the target
+	     process (if it has such), and as a flag indicating that a
+	     target is active.  These functions should be split out
+	     into seperate variables, especially since GDB will
+	     someday have a notion of debugging several processes.  */
+	  inferior_ptid = magic_null_ptid;
+	  fake_pid_p = 1;
+	}
 
-      remote_add_inferior (ptid_get_pid (inferior_ptid), -1);
+      inf = remote_add_inferior (ptid_get_pid (inferior_ptid), -1);
+      inf->fake_pid_p = fake_pid_p;
 
       /* Always add the main thread.  */
       add_thread_silent (inferior_ptid);

[-- Attachment #5: 04-allow_multi_on_remote.diff --]
[-- Type: text/x-patch, Size: 3066 bytes --]

Allow the remote protocol thread id extension on plain target remote.

From: Pedro Alves <palves@redhat.com>


---
 gdb/gdbserver/server.c |    4 ++--
 gdb/remote.c           |   15 +++++++++------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index a3bc6c9..5ae6795 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -2140,7 +2140,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vAttach;", 8) == 0)
     {
-      if (!multi_process && target_running ())
+      if ((!extended_protocol || !multi_process) && target_running ())
 	{
 	  fprintf (stderr, "Already debugging a process\n");
 	  write_enn (own_buf);
@@ -2152,7 +2152,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vRun;", 5) == 0)
     {
-      if (!multi_process && target_running ())
+      if ((!extended_protocol || !multi_process) && target_running ())
 	{
 	  fprintf (stderr, "Already debugging a process\n");
 	  write_enn (own_buf);
diff --git a/gdb/remote.c b/gdb/remote.c
index c5c9481..e78853c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -359,7 +359,7 @@ free_private_thread_info (struct private_thread_info *info)
 static int
 remote_multi_process_p (struct remote_state *rs)
 {
-  return rs->extended && rs->multi_process_aware;
+  return rs->multi_process_aware;
 }
 
 /* This data could be associated with a target, but we do not always
@@ -1713,7 +1713,7 @@ set_general_process (void)
   struct remote_state *rs = get_remote_state ();
 
   /* If the remote can't handle multiple processes, don't bother.  */
-  if (!remote_multi_process_p (rs))
+  if (!rs->extended || !remote_multi_process_p (rs))
     return;
 
   /* We only need to change the remote current thread if it's pointing
@@ -3885,8 +3885,7 @@ remote_query_supported (void)
       char *q = NULL;
       struct cleanup *old_chain = make_cleanup (free_current_contents, &q);
 
-      if (rs->extended)
-	q = remote_query_supported_append (q, "multiprocess+");
+      q = remote_query_supported_append (q, "multiprocess+");
 
       if (remote_support_xml)
 	q = remote_query_supported_append (q, remote_support_xml);
@@ -7440,7 +7439,7 @@ extended_remote_kill (struct target_ops *ops)
   struct remote_state *rs = get_remote_state ();
 
   res = remote_vkill (pid, rs);
-  if (res == -1 && !remote_multi_process_p (rs))
+  if (res == -1 && !(rs->extended && remote_multi_process_p (rs)))
     {
       /* Don't try 'k' on a multi-process aware stub -- it has no way
 	 to specify the pid.  */
@@ -9773,7 +9772,11 @@ remote_supports_multi_process (void)
 {
   struct remote_state *rs = get_remote_state ();
 
-  return remote_multi_process_p (rs);
+  /* Only extended-remote handles being attached to multiple
+     processes, even though plain remote can use the multi-process
+     thread id extensions, so that GDB knows the target process's
+     PID.  */
+  return rs->extended && remote_multi_process_p (rs);
 }
 
 int

[-- Attachment #6: 05-abstract_if_necessary.diff --]
[-- Type: text/x-patch, Size: 4483 bytes --]

Hide getting at the current process's PID behind a target method.

From: Pedro Alves <palves@redhat.com>


---
 gdb/linux-nat.c |   18 ++++++++++++++++--
 gdb/remote.c    |   26 ++++++++++++++++++++++++++
 gdb/target.c    |    5 +++++
 gdb/target.h    |    4 ++++
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 17236ec..1d06352 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -5007,6 +5007,16 @@ make_cleanup_target_file_close (int fd)
   return make_cleanup (do_target_file_close, fdp);
 }
 
+static int
+linux_nat_current_process_id (LONGEST *pid)
+{
+  if (!target_has_execution)
+    noprocess ();
+
+  *pid = ptid_get_pid (inferior_ptid);
+  return 0;
+}
+
 static void
 linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
@@ -5038,11 +5048,13 @@ linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 
   if (!explicit_pid)
     {
+      LONGEST tpid;
+
       if (!target_has_execution)
 	error (_("No current process: you must name one."));
-      if (current_inferior ()->fake_pid_p)
+      if (target_current_process_id (&tpid) == -1)
 	error (_("Can't determine the current process's PID: you must name one."));
-      pid = ptid_get_pid (inferior_ptid);
+      pid = tpid;
     }
 
   printf_filtered (_("process %ld\n"), pid);
@@ -6077,6 +6089,8 @@ linux_nat_add_target (struct target_ops *t)
   t->to_file_pread = linux_nat_file_pread;
   t->to_file_close = linux_nat_file_close;
 
+  t->to_current_process_id = linux_nat_current_process_id;
+
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable
diff --git a/gdb/remote.c b/gdb/remote.c
index e78853c..2bd7d13 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9779,6 +9779,30 @@ remote_supports_multi_process (void)
   return rs->extended && remote_multi_process_p (rs);
 }
 
+/* Return in *PID the current inferior's target process ID.  Returns 0
+   on success, and -1 if not possible to determine the target PID.
+   Throws an error if there is no current inferior.  */
+
+static int
+remote_current_process_id (LONGEST *pid)
+{
+  if (!target_has_execution)
+    noprocess ();
+
+  /* Add query to remote target side here if/when necessary.  */
+
+  /* Default to assuming there's a 1:1 mapping between RSP process ID
+     and target process ID.  */
+
+  /* With no multi-process extensions, we have nothing to fall back
+     to.  */
+  if (current_inferior ()->fake_pid_p)
+    return -1;
+
+  *pid = ptid_get_pid (inferior_ptid);
+  return 0;
+}
+
 int
 remote_supports_cond_tracepoints (void)
 {
@@ -10715,6 +10739,8 @@ Specify the serial device it is connected to\n\
   remote_ops.to_file_pread = remote_hostio_pread;
   remote_ops.to_file_close = remote_hostio_close;
   remote_ops.to_file_unlink = remote_hostio_unlink;
+
+  remote_ops.to_current_process_id = remote_current_process_id;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
diff --git a/gdb/target.c b/gdb/target.c
index 74238a5..1422117 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -704,6 +704,8 @@ update_current_target (void)
       INHERIT (to_file_close, t);
       INHERIT (to_file_unlink, t);
 
+      INHERIT (to_current_process_id, t);
+
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -950,6 +952,9 @@ update_current_target (void)
   de_fault (to_file_unlink,
 	    (int (*) (const char *, int *))
 	    tcomplain);
+  de_fault (to_current_process_id,
+	    (int (*) (LONGEST *))
+	    tcomplain);
 
 #undef de_fault
 
diff --git a/gdb/target.h b/gdb/target.h
index 96176a5..449be04 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -821,6 +821,7 @@ struct target_ops
        occurs (and set *TARGET_ERRNO).  */
     int (*to_file_unlink) (const char *filename, int *target_errno);
 
+    int (*to_current_process_id) (LONGEST *pid);
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1789,6 +1790,9 @@ extern void update_target_permissions (void);
 #define target_file_unlink(filename, target_errno)		\
   (*current_target.to_file_close) (filename, target_errno)
 
+#define target_current_process_id(PID)		\
+  (*current_target.to_current_process_id) (PID)
+
 \f
 /* Imported from machine dependent code.  */
 

[-- Attachment #7: series --]
[-- Type: text/plain, Size: 128 bytes --]

01-target_fileio.diff
02-proc_access_target.diff
03-process_id.diff
04-allow_multi_on_remote.diff
05-abstract_if_necessary.diff

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command)
  2012-01-11 16:38                                               ` Pedro Alves
@ 2012-01-11 18:32                                                 ` Ulrich Weigand
  0 siblings, 0 replies; 83+ messages in thread
From: Ulrich Weigand @ 2012-01-11 18:32 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, jan.kratochvil, sergiodj

Pedro Alves wrote:
> On 01/09/2012 03:43 PM, Ulrich Weigand wrote:
> > - We say instead that, yes, we *want* OS PIDs to be used as first-
> >   class user interface elements.  But this means to me that we
> >   need to more generally make OS PIDs present in GDB common code
> >   so that common code is at least able to associate its internal
> >   notions of "inferior" with those IDs.  At a minimum, this would
> >   imply we no longer consider "ptid_t" values to be opaque to
> >   GDB common code, but rather enforce that they agree with user-
> >   visible OS PID values.
> 
> Note that I'm not talking about the notion of a "process id" escape
> escape to common/core code, but only to the linux gdbarch/osabi
> specific bits; or other code that can deal with it, guarded by
> "is there a notion of a process id on this target.

Ah, I see.  OK, I guess this make sense ...

> > I don't quite understand what you mean here.  Could you elaborate
> > how you propose to implement this routine "return the target process
> > ID of a given GDB inferior/thread" without remote interface changes?
> > This was exactly the "magic 42000" problem I was running into ...
> 
> As mentioned before, by broadcasting support for multi-process extensions
> even with "target remote" (but don't allow debugging multiple processes),
> and defaulting to assume a 1:1 mapping between target process id
> and RSP process id, until some target needs to do something else, at
> which point we define a new packet.

OK, that was the piece I was missing.  Yes, if we enable the multi-process
extension, that should work.

> I've spent a bit today prototyping /proc access this way the way
> I was imagining it.  See the attached patch series.  This is far from
> complete.  It's just enough to get something working.

Ah, thanks!  I should have posted my work-in-progress patch series;
I had already implemented most of what's in your patches, except for
the process-id bits.  Sorry for causing you extra work!


So, both the features:
- enable multi-process extension to get better PID
- have an inferior flag to specify whether the PID is "fake" or
  corresponds to a target PID
make sense to me, and looks like they should be enabled anyway.  If we
can then implement /proc access without any further protocol extension,
I don't really have any objection ...

I'll integrate your suggestions with my WIP patches and see how far
I get.


> > I must admit I don't see what the benefit of this is supposed to be.
> > This seems to me to be the exact use case that "annex" is there to
> > cover: a bunch of information with related content semantics, which
> > are all accessed the same way, and the exact set is somewhat dynamic.
> > Not using the annex would mean defining a whole bunch of new packet
> > types, duplicated boilerplate code in GDB and gdbserver to hook them
> > up, and then still the drawback that every new /proc file that may
> > come up in the future will require extra code (including new gdbserver-side
> > code!) to support.  And for all those drawbacks, I don't see any single
> > benefit ...  Maybe you can elaborate?
> 
> - Decoupling of the objects in question from a "/proc" idea, so they
> can be more generally used in other scenarios, like e.g., a remote
> protocol implementation of target_pid_to_str (TARGET_OBJECT_PROC/exe).
> - Let GDB have a finer grained idea of what subset of /proc-ish objects
> are supported upfront (through qSupported), without any new mechanism.

I still don't quite see why we cannot do the same with using the annex.
In both cases, users in GDB would do some form of target_read and check
the error code; the only difference is whether they use TARGET_OBJECT_PROC
with a non-NULL annex, or else TARGET_OBJECT_PROC_xxx without annex.

But I guess if we don't do TARGET_OBJECT_PROC at all it doesn't matter.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH 0/4 v2] Implement support for SystemTap probes on userspace
@ 2012-04-06  3:28 Sergio Durigan Junior
  2012-04-06  3:32 ` [PATCH 1/4 v2] Refactor internal variable mechanism Sergio Durigan Junior
                   ` (3 more replies)
  0 siblings, 4 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-06  3:28 UTC (permalink / raw)
  To: gdb-patches

Hello again,

Sorry for the long delay to resubmit these patches.  Well, here they
are, with all comments addressed.  I will CC: the people who have made
comments in the last attempt.

Here is a full explanation of what these patches are supposed to do:

   http://sourceware.org/ml/gdb-patches/2012-03/msg00353.html

I regtested all of the components of this patch in a x86_64, PPC64,
S390x and ARM archs, without regressions.

Comments and reviews are welcome.  This time, I promise I'll resubmit
the patches in a shorter time :-).

Thank you,

-- 
Sergio

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH 1/4 v2] Refactor internal variable mechanism
  2012-04-06  3:28 [PATCH 0/4 v2] Implement support for SystemTap probes on userspace Sergio Durigan Junior
@ 2012-04-06  3:32 ` Sergio Durigan Junior
  2012-04-06  3:36 ` [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-06  3:32 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is the first patch of the series.  This piece of code didn't change
from the last time.

You can see the last version of it in:

    http://sourceware.org/ml/gdb-patches/2012-03/msg00354.html

Is this OK to check-in?

gdb/ChangeLog
2012-07-04  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 103ef30..54e39ef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6589,7 +6589,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)
@@ -7011,6 +7012,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)
 {
@@ -7299,7 +7309,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 057b441..fac6b44 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4943,7 +4943,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;
@@ -5122,6 +5123,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)
@@ -5132,7 +5142,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 c23803a..7f2da6f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1588,7 +1588,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
@@ -1687,18 +1694,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.
 
@@ -1771,7 +1799,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:
@@ -1967,6 +1996,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 4d04a20..f1f72cd 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -748,10 +748,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] 83+ messages in thread

* [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes
  2012-04-06  3:28 [PATCH 0/4 v2] Implement support for SystemTap probes on userspace Sergio Durigan Junior
  2012-04-06  3:32 ` [PATCH 1/4 v2] Refactor internal variable mechanism Sergio Durigan Junior
@ 2012-04-06  3:36 ` Sergio Durigan Junior
  2012-04-11 19:06   ` Jan Kratochvil
  2012-04-06  3:37 ` [PATCH 4/4 v2] Documentation and testsuite changes Sergio Durigan Junior
  2012-04-06  4:11 ` [PATCH 3/4 v2] Use longjmp and exception probes when available Sergio Durigan Junior
  3 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-06  3:36 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Tom Tromey, Mark Kettenis, Jan Kratochvil

Hi,

This is the second and largest patch.  It received lots of comments in
the first round, and I addressed all of them (at least I think so).

Please, I would like you to take a look and see what you think of this
version.  As I said in the first e-mail, I regtested the changes here
and everything is passing.

The last version can be found here:

    http://sourceware.org/ml/gdb-patches/2012-03/msg00355.html

In this new version, I created the new file `probe.c', which contains
definitions for a new command called `info probes'.  This command can
take 2 arguments: `stap' and `all'.  I also renamed the breakpoint
command to `break -probe-stap', or `break -pstap' as an alias.  This
way, we can at least have a way to extend these SDT probes if needed (by
converting UST probes to use the same set of commands, for example).

I have also put arch-specific bits in ${arch}-tdep.[ch] files, instead
of ${arch}-linux-tdep.[ch].  Note, however, that for PPC and ARM
architectures I just used the *-linux-tdep.c files, since there is no
*-tdep.c file (and I didn't feel confident to create a new one just for that).

As a last note, I splitted the patch series in 4 patches (instead of 3),
so the documentation and testsuite bits are in patch #4 now.

Another minor comments were also addressed.

Is this OK to check-in?

gdb/ChangeLog
2012-07-04  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Tom Tromey  <tromey@redhat.com>

	* Makefile.in (SFILES): Add `stap-probe'.
	(COMMON_OBS): Likewise.
	(HFILES_NO_SRCDIR): Likewise.
	* NEWS: Mention support for 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 `stap-probe.h'.
	(bkpt_stap_probe_breakpoint_ops): New variable.
	(modify_semaphore): New function.
	(insert_bp_location): Set SystemTap probe semaphore when successfully
	inserting the breakpoint.
	(remove_breakpoint_1): Clear SystemTap probe semaphore when removing
	the breakpoint.
	(momentary_breakpoint_from_master): Use the `semaphore' 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_stap_probe_create_sals_from_address): New function.
	(bkpt_stap_probe_decode_linespec): Likewise.
	(initialize_breakpoint_ops): Initializing breakpoint_ops from
	SystemTap probes.
	* breakpoint.h (struct bp_location) <semaphore>: 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.
	* dbxread.c (aout_sym_fns): Likewise.
	* elfread.c: Include `stap-probe.h' and `arch-utils.h'.
	(STAP_BASE_SECTION_NAME): New define.
	(stap_probe_key): New variable.
	(struct stap_probe_per_objfile): New struct.
	(handle_probe): New function.
	(get_base_address_1): New function.
	(get_base_address): Likewise.
	(elf_get_probes): Likewise.
	(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 SystemTap
	probes.
	* 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 SystemTap
	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.
	* 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 (struct sym_probe_fns): New struct.
	(struct sym_fns) <sym_probe_fns>: New field.
	* symtab.c (init_sal): Initialize `semaphore' field.
	* symtab.h (struct symtab_and_line) <semaphore>: 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             |    6 +
 gdb/amd64-tdep.c     |   10 +
 gdb/arm-linux-tdep.c |  132 ++++
 gdb/ax-gdb.c         |    8 +-
 gdb/ax-gdb.h         |    5 +
 gdb/breakpoint.c     |   59 ++-
 gdb/breakpoint.h     |   14 +
 gdb/cli/cli-utils.c  |   41 ++
 gdb/cli/cli-utils.h  |   11 +
 gdb/coffread.c       |    1 +
 gdb/dbxread.c        |    1 +
 gdb/elfread.c        |  334 ++++++++++
 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          |   65 ++
 gdb/s390-tdep.c      |   26 +-
 gdb/somread.c        |    1 +
 gdb/stap-probe.c     | 1790 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/stap-probe.h     |  161 +++++
 gdb/symfile.h        |   58 ++
 gdb/symtab.c         |    1 +
 gdb/symtab.h         |    4 +
 gdb/tracepoint.c     |   30 +
 gdb/xcoffread.c      |    1 +
 34 files changed, 3690 insertions(+), 31 deletions(-)
 create mode 100644 gdb/probe.c
 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 44d76f2..392405c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -724,8 +724,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 \
@@ -821,7 +821,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
-gnulib/stddef.in.h inline-frame.h skip.h \
+gnulib/stddef.in.h inline-frame.h skip.h stap-probe.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
 common/linux-osdata.h gdb-dlfcn.h
 
@@ -910,7 +910,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 stap-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 5885d32..fd95c05 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,12 @@
 
 *** Changes since GDB 7.4
 
+* GDB now has support for SystemTap <sys/sdt.h> probes.  You can set a
+  breakpoint using the new "-p" or "-probe" 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 a193099..70bcdc7 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -2688,6 +2688,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..43d5b29 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 "stap-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 SystemTap probes.  */
+static struct breakpoint_ops bkpt_stap_probe_breakpoint_ops;
+
 /* A reference-counted struct command_line.  This lets multiple
    breakpoints share a single command list.  */
 struct counted_command_line
@@ -2185,6 +2190,13 @@ insert_bp_location (struct bp_location *bl,
 	  /* No overlay handling: just set the breakpoint.  */
 
 	  val = bl->owner->ops->insert_location (bl);
+
+	  if (val == 0)
+	    {
+	      /* Set the semaphore, since the breakpoint insertion has
+		 succeeded.  */
+	      stap_semaphore_up (bl->semaphore, bl->gdbarch);
+	    }
 	}
       else
 	{
@@ -3168,6 +3180,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
 	  || bl->section == NULL
 	  || !(section_is_overlay (bl->section)))
 	{
+	  stap_semaphore_down (bl->semaphore, bl->gdbarch);
+
 	  /* No overlay handling: just remove the breakpoint.  */
 	  val = bl->owner->ops->remove_location (bl);
 	}
@@ -8138,6 +8152,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->semaphore = orig->loc->semaphore;
 
   if (orig->loc->source_file != NULL)
     copy->loc->source_file = xstrdup (orig->loc->source_file);
@@ -8223,6 +8238,7 @@ add_location_to_breakpoint (struct breakpoint *b,
   loc->requested_address = sal->pc;
   loc->address = adjusted_address;
   loc->pspace = sal->pspace;
+  loc->semaphore = sal->semaphore;
   gdb_assert (loc->pspace != NULL);
   loc->section = sal->section;
   loc->gdbarch = loc_gdbarch;
@@ -8962,6 +8978,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;
+
+  /* Matching breakpoints on SystemTap probes (`-pstap' or `-probe-stap').  */
+  if (arg && ((strncmp (arg, "-probe-stap", 11) == 0 && isspace (arg[11]))
+	      || (strncmp (arg, "-pstap", 6) == 0 && isspace (arg[6]))))
+    ops = &bkpt_stap_probe_breakpoint_ops;
+  else
+    ops = &bkpt_breakpoint_ops;
 
   create_breakpoint (get_current_arch (),
 		     arg,
@@ -8969,7 +8993,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 +12467,33 @@ momentary_bkpt_print_mention (struct breakpoint *b)
   /* Nothing to mention.  These breakpoints are internal.  */
 }
 
+/* Specific methods for SystemTap probe breakpoints.  */
+
+static void
+bkpt_stap_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_stap_probe (arg, canonical);
+
+  *copy_arg = xstrdup (canonical->addr_string);
+  lsal.canonical = xstrdup (*copy_arg);
+
+  VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+bkpt_stap_probe_decode_linespec (struct breakpoint *b, char **s,
+				 struct symtabs_and_lines *sals)
+{
+  *sals = parse_stap_probe (s, NULL);
+  if (!sals->sals)
+    error (_("probe not found"));
+}
+
 /* The breakpoint_ops structure to be used in tracepoints.  */
 
 static void
@@ -14939,6 +14990,12 @@ initialize_breakpoint_ops (void)
   ops->print_it = momentary_bkpt_print_it;
   ops->print_mention = momentary_bkpt_print_mention;
 
+  /* SystemTap probe breakpoints.  */
+  ops = &bkpt_stap_probe_breakpoint_ops;
+  *ops = bkpt_breakpoint_ops;
+  ops->create_sals_from_address = bkpt_stap_probe_create_sals_from_address;
+  ops->decode_linespec = bkpt_stap_probe_decode_linespec;
+
   /* GNU v3 exception catchpoints.  */
   ops = &gnu_v3_exception_catchpoint_ops;
   *ops = bkpt_breakpoint_ops;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e0eeeaa..2e6b953 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -418,6 +418,20 @@ struct bp_location
      processor's architectual constraints.  */
   CORE_ADDR requested_address;
 
+  /* If the location comes from a SystemTap probe point, and the probe
+     has an associated semaphore variable, then this is the address of
+     the semaphore.  Otherwise, this is zero.
+
+     A SystemTap semaphore is useful when the computation of a probe's
+     argument is too expensive: it may gate invocations of a probe, and must
+     be set to a non-zero value to guarantee that the probe will be hit.
+     Semaphores are treated as a counter, and the tool (GDB, in this case)
+     should increment it to enable, and decrement the semaphore when finished.
+     Overflow is currently ignored, so a large number of attaches could
+     actually cause the probe to be disabled.  This is not likely to happen
+     in practice, however.  */
+  CORE_ADDR semaphore;
+
   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 30bf3f7..f5b9fe0 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/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 9f8a7e8..d7fa725 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -36,6 +36,8 @@
 #include "demangle.h"
 #include "psympriv.h"
 #include "filenames.h"
+#include "stap-probe.h"
+#include "arch-utils.h"
 #include "gdbtypes.h"
 #include "value.h"
 #include "infcall.h"
@@ -43,6 +45,11 @@
 #include "regcache.h"
 #include "bcache.h"
 
+/* The name of the SystemTap section where we will find information about
+   the probes.  */
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
 extern void _initialize_elfread (void);
 
 /* Forward declarations.  */
@@ -60,6 +67,21 @@ struct elfinfo
     asection *mdebugsect;	/* Section pointer for .mdebug section */
   };
 
+/* Per-objfile data for SystemTap probe info.  */
+
+static const struct objfile_data *stap_probe_key = NULL;
+
+/* Per-objfile data about SystemTap probes.  */
+
+struct stap_probe_per_objfile
+  {
+    /* The number of probes in this objfile.  */
+    int stap_num_probes;
+
+    /* Pointer to array of STAP_NUM_PROBES elements with the probes.  */
+    struct stap_probe *probes;
+  };
+
 static void free_elfinfo (void *);
 
 /* Minimal symbols located at the GOT entries for .plt - that is the real
@@ -1579,7 +1601,314 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
     complaint (&symfile_complaints,
 	       _("elf/stab section information missing for %s"), filename);
 }
+
+/* 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 int
+handle_probe (struct objfile *objfile, struct sdt_note *el,
+	      struct stap_probe *ret, 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;
+
+  ret->gdbarch = gdbarch;
+
+  /* Provider and the name of the probe.  */
+  ret->provider = &el->data[3 * size];
+  ret->name = memchr (ret->provider, '\0',
+		      (char *) el->data + el->size - ret->provider);
+  /* Making sure there is a name.  */
+  if (!ret->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 0;
+    }
+  else
+    ++ret->name;
+
+  /* Retrieving the probe's address.  */
+  ret->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->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.  */
+  ret->args = memchr (ret->name, '\0',
+		      (char *) el->data + el->size - ret->name);
+
+  if (ret->args != NULL)
+    ++ret->args;
+
+  if (ret->args == NULL || (memchr (ret->args, '\0',
+				    (char *) el->data + el->size - ret->name)
+			    != el->data + el->size - 1))
+    {
+      /* Although failing here is not good, it is still possible to use a
+	 probe without arguments.  That's why we don't return zero.  */
+      complaint (&symfile_complaints, _("corrupt probe argument when "
+					"reading `%s'"), objfile->name);
+      ret->args = NULL;
+    }
+
+  return 1;
+}
+
+/* Helper function which tries to find the base address of the SystemTap
+   base section named STAP_BASE_SECTION_NAME.  */
+
+static void
+get_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_base_address (bfd *obfd, bfd_vma *base)
+{
+  asection *ret = NULL;
+
+  bfd_map_over_sections (obfd, get_base_address_1, (void *) &ret);
+
+  if (!ret)
+    {
+      complaint (&symfile_complaints, _("could not obtain base address for "
+					"SystemTap section."));
+      return 0;
+    }
+
+  if (base)
+    *base = ret->vma;
+
+  return 1;
+}
+
+/* Implementation of `sym_get_probes', as documented in symfile.h.  */
+
+static struct stap_probe *
+elf_get_probes (struct objfile *objfile, int *num_probes)
+{
+  struct stap_probe *ret = NULL;
+  struct stap_probe_per_objfile *probes_per_objfile;
+
+  /* Initially, no probes.  */
+  *num_probes = 0;
+
+  /* Have we parsed this objfile's probes already?  */
+  probes_per_objfile = objfile_data (objfile, stap_probe_key);
+
+  if (!probes_per_objfile)
+    {
+      /* If we are here, then this is the first time we are parsing the
+	 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;
+      int cur_probe = 0;
+      int n = 0;
+
+      if (!elf_tdata (obfd)->sdt_note_head)
+	{
+	  /* There isn't any probe here.  */
+	  return NULL;
+	}
+
+      if (!get_base_address (obfd, &base))
+	{
+	  /* There was an error finding the base address for the section.
+	     Just return NULL.  */
+	  return NULL;
+	}
+
+      /* Allocating space for probe info.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head;
+	   iter;
+	   iter = iter->next, ++n);
+
+      ret = xcalloc (n, sizeof (struct stap_probe));
+
+      /* Parsing each probe's information.  */
+      for (iter = elf_tdata (obfd)->sdt_note_head, cur_probe = 0;
+	   iter;
+	   iter = iter->next)
+	{
+	  /* We first have to handle all the information about the
+	     probe which is present in the section.  */
+	  if (handle_probe (objfile, iter, &ret[cur_probe], base))
+	    {
+	      /* We just increment `cur_probe' if `handle_probe' returned
+		 non-zero.  This way, we can make sure that only probes which
+		 were successfully parsed are inserted in the list of known
+		 probes.  */
+	      ++cur_probe;
+	    }
+	}
+
+      if (!cur_probe)
+	{
+	  /* If we are here, it means we have failed to parse every known
+	     probe.  */
+	  xfree (ret);
+	  complaint (&symfile_complaints, _("could not parse probe(s) "
+					    "from inferior"));
+	  return NULL;
+	}
+
+      /* Reallocating the list of probes in order to save space.  */
+      if (cur_probe < n)
+	ret = xrealloc (ret, cur_probe * sizeof (struct stap_probe));
+
+      /* Creating a cache for these probes in the objfile's registry.  */
+      probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
+
+      probes_per_objfile->stap_num_probes = cur_probe;
+      probes_per_objfile->probes = ret;
+
+      set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
+    }
+  else
+    ret = probes_per_objfile->probes;
+
+  *num_probes = probes_per_objfile->stap_num_probes;
+
+  return ret;
+}
+
+/* Implementation of `sym_get_probe_argument_count', as documented in
+   symfile.h.  */
+
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+			      struct stap_probe *probe)
+{
+  const char *pargs = probe->args;
+
+  if (!pargs || !*pargs || *pargs == ':')
+    {
+      /* No arguments.  */
+      return 0;
+    }
+
+  return stap_get_probe_argument_count (probe);
+}
+
+/* Implementation of `sym_evaluate_probe_argument', as documented in
+   symfile.h.  */
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+			     struct stap_probe *probe,
+			     struct frame_info *frame,
+			     int n)
+{
+  return stap_evaluate_probe_argument (objfile, probe, frame, n);
+}
+
+/* Implementation of `sym_compile_to_ax', as documented in symfile.h.  */
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+		   struct stap_probe *probe,
+		   struct agent_expr *expr,
+		   struct axs_value *value,
+		   int n)
+{
+  stap_compile_to_ax (objfile, probe, 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 i;
+  struct stap_probe_per_objfile *p = objfile_data (objfile, stap_probe_key);
+
+  if (!p)
+    {
+      /* No probe to relocate.  */
+      return;
+    }
+
+  for (i = 0; i < p->stap_num_probes; i++)
+    {
+      p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+      if (p->probes[i].sem_addr)
+	p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
+    }
+}
+
+/* Helper function used to free the space allocated for storing SystemTap
+   probe information.  */
+
+static void
+stap_probe_key_free (struct objfile *objfile, void *d)
+{
+  int i;
+  struct stap_probe_per_objfile *data = d;
+
+  for (i = 0; i < data->stap_num_probes; i++)
+    stap_free_parsed_args (data->probes[i].parsed_args);
+  xfree (data->probes);
+  xfree (data);
+}
+
 \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 =
@@ -1594,6 +1923,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
 };
 
@@ -1612,6 +1942,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
 };
 
@@ -1629,6 +1960,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
 };
 
@@ -1645,6 +1977,8 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
 void
 _initialize_elfread (void)
 {
+  stap_probe_key
+    = register_objfile_data_with_cleanup (NULL, stap_probe_key_free);
   add_symtab_fns (&elf_sym_fns);
 
   elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
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..72deabf 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -795,6 +795,11 @@ objfile_relocate1 (struct objfile *objfile,
 				obj_section_addr (s));
     }
 
+  /* Relocating SystemTap 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..04b123b
--- /dev/null
+++ b/gdb/probe.c
@@ -0,0 +1,65 @@
+/* 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/>.  */
+
+#include "defs.h"
+#include "stap-probe.h"
+#include "command.h"
+#include "cli/cli-cmds.h"
+
+/* Implementation of the `info probes' command.  */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+  /* If we are here, it means the user has not specified any
+     argument, or has specified `all'.  In either case, we should
+     print information about all types of probes.  */
+  info_probes_stap_command (arg, from_tty);
+}
+
+void _initialize_probe (void);
+
+void
+_initialize_probe (void)
+{
+  static struct cmd_list_element *info_probes_cmdlist;
+
+  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);
+
+  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);
+}
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..f12af12
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,1790 @@
+/* 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 "vec.h"
+#include "ui-out.h"
+#include "gdb_regex.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 <ctype.h>
+
+/* The maximum number of arguments that a probe can have,
+   as defined in <sys/sdt.h>.  */
+
+#define STAP_MAX_ARGS 12
+
+/* 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;
+};
+
+/* Structure that holds information about all arguments of a probe.  */
+
+struct stap_args_info
+{
+  /* The number of valid parsed arguments.  */
+  int n_args;
+
+  /* The probe to which these arguments belong.  */
+  struct stap_probe *probe;
+
+  /* Information about each argument.  This is an array of `stap_probe_arg',
+     with each entry representing one argument.  */
+  struct stap_probe_arg *args;
+};
+
+/* 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
+};
+
+/* This dummy variable is used when parsing a probe's argument fails.
+   In this case, the number of arguments for this probe is zero, so that's
+   why this variable is useful.  */
+
+static struct stap_args_info dummy_stap_args_info =
+  { 0, NULL, NULL };
+
+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;
+}
+
+/* Helper function which is responsible for freeing the space allocated to
+   hold information about a probe's arguments.  */
+
+static void
+stap_free_args_info (void *args_info_ptr)
+{
+  struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
+  int i;
+
+  for (i = 0; i < a->n_args; i++)
+    xfree (a->args[i].aexpr);
+
+  xfree (a->args);
+  xfree (a);
+}
+
+/* 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 stap_args_info *args_info;
+  struct cleanup *back_to;
+  const char *cur = probe->args;
+  int current_arg = -1;
+
+  /* This is a state-machine parser, which means we will always be
+     in a known state when parsing an argument.  The state could be
+     either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
+     we are parsing the bitness-definition part (i.e., `4@'), or
+     `PARSE_ARG' if we are actually parsing the argument part.  */
+  enum
+    {
+      NEW_ARG,
+      BITNESS,
+      PARSE_ARG,
+    } current_state;
+
+  /* For now, we assume everything is not going to work.  */
+  probe->parsed_args = &dummy_stap_args_info;
+
+  if (!cur || !*cur || *cur == ':')
+    return;
+
+  args_info = xmalloc (sizeof (struct stap_args_info));
+  args_info->n_args = 0;
+  back_to = make_cleanup (stap_free_args_info, args_info);
+  args_info->args = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
+
+  current_state = NEW_ARG;
+
+  while (*cur)
+    {
+      switch (current_state)
+	{
+	case NEW_ARG:
+	  ++current_arg;
+
+	  if (current_arg >= STAP_MAX_ARGS)
+	    {
+	      complaint (&symfile_complaints,
+			 _("probe `%s' has more arguments than the maximum "
+			   "allowed"), probe->name);
+	      do_cleanups (back_to);
+	      return;
+	    }
+
+	  current_state = BITNESS;
+	  break;
+
+	case BITNESS:
+	    {
+	      enum stap_arg_bitness b;
+	      int got_minus = 0;
+
+	      /* 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] != '@')
+		{
+		  current_state = PARSE_ARG;
+		  args_info->args[current_arg].bitness
+		    = STAP_ARG_BITNESS_UNDEFINED;
+		  break;
+		}
+
+	      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->name);
+		  do_cleanups (back_to);
+		  return;
+		}
+
+	      args_info->args[current_arg].bitness = b;
+	      args_info->args[current_arg].atype
+		= stap_get_expected_argument_type (probe->gdbarch, b);
+
+	      /* Discard the number and the `@' sign.  */
+	      cur += 2;
+
+	      /* Move on.  */
+	      current_state = PARSE_ARG;
+	    }
+	  break;
+
+	case PARSE_ARG:
+	    {
+	      struct expression *ret;
+
+	      ret = stap_parse_argument (&cur,
+					 args_info->args[current_arg].atype,
+					 probe->gdbarch);
+
+	      if (stap_expression_debug)
+		dump_raw_expression (ret, gdb_stdlog,
+				     "before conversion to prefix form");
+
+	      prefixify_expression (ret);
+
+	      if (stap_expression_debug)
+		dump_prefix_expression (ret, gdb_stdlog);
+
+	      args_info->args[current_arg].aexpr = ret;
+
+	      ++args_info->n_args;
+
+	      /* Start it over again.  */
+	      cur = skip_spaces_const (cur);
+	      current_state = NEW_ARG;
+	    }
+	  break;
+	}
+
+      if (!*cur && current_state != NEW_ARG)
+	{
+	  /* We reached the end of the argument string, but we're
+	     still in the middle of the process of parsing an argument.
+	     It means the argument string is malformed.  */
+	  complaint (&symfile_complaints,
+		     _("malformed argument for probe `%s'"),
+		     probe->name);
+	  do_cleanups (back_to);
+	  return;
+	}
+    }
+
+  args_info->args = xrealloc (args_info->args,
+			      args_info->n_args
+			      * sizeof (struct stap_probe_arg));
+  args_info->probe = probe;
+
+  probe->parsed_args = args_info;
+
+  discard_cleanups (back_to);
+}
+
+/* See definition in stap-probe.h.  */
+
+int
+stap_get_probe_argument_count (struct stap_probe *probe)
+{
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments (probe);
+
+  return probe->parsed_args->n_args;
+}
+
+/* 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 == '=');
+}
+
+/* See definition in stap-probe.h.  */
+
+struct value *
+stap_evaluate_probe_argument (struct objfile *objfile,
+			      struct stap_probe *probe,
+			      struct frame_info *frame,
+			      int n)
+{
+  int pos = 0;
+
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments (probe);
+
+  if (!probe->parsed_args->args
+      || n >= probe->parsed_args->n_args)
+    return NULL;
+
+  /* This is needed because on some architectures (e.g., ARM) we need
+     the frame's gdbarch in order to compute the value of the frame
+     pointer.  */
+  probe->parsed_args->args[n].aexpr->gdbarch = get_frame_arch (frame);
+
+  return evaluate_subexp_standard (probe->parsed_args->args[n].atype,
+				   probe->parsed_args->args[n].aexpr,
+				   &pos, EVAL_NORMAL);
+}
+
+/* See definition in stap-probe.h.  */
+
+void
+stap_compile_to_ax (struct objfile *objfile,
+		    struct stap_probe *probe,
+		    struct agent_expr *expr,
+		    struct axs_value *value,
+		    int n)
+{
+  union exp_element *pc;
+
+  if (!probe->parsed_args)
+    stap_parse_probe_arguments (probe);
+
+  if (!probe->parsed_args->args
+      || n >= probe->parsed_args->n_args)
+    return;
+
+  pc = probe->parsed_args->args[n].aexpr->elts;
+  gen_expr (probe->parsed_args->args[n].aexpr, &pc, expr, value);
+
+  require_rvalue (expr, value);
+  value->type = probe->parsed_args->args[n].atype;
+}
+
+/* See comments in stap-probe.h.  */
+
+struct value *
+stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
+{
+  struct stap_probe *probe;
+  struct objfile *objfile;
+  int 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,
+								  frame,
+								  n);
+}
+
+/* This function frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+void
+stap_free_parsed_args (struct stap_args_info *parsed_args)
+{
+  int i;
+
+  if (!parsed_args
+      || parsed_args == &dummy_stap_args_info
+      || parsed_args->n_args == 0)
+    return;
+
+  for (i = 0; i < parsed_args->n_args; i++)
+    xfree (parsed_args->args[i].aexpr);
+
+  xfree (parsed_args->args);
+  xfree (parsed_args);
+}
+
+/* A utility structure.  A VEC of these is built when handling "info
+   probes".  */
+
+struct stap_probe_and_objfile
+{
+  /* The probe.  */
+  struct stap_probe *probe;
+
+  /* The probe's objfile.  */
+  struct objfile *objfile;
+};
+
+typedef struct stap_probe_and_objfile stap_entry;
+DEF_VEC_O (stap_entry);
+
+/* 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.
+   Each argument is a regexp, or NULL, which matches anything.  */
+
+static VEC (stap_entry) *
+collect_probes (char *objname, char *provider, char *probe)
+{
+  struct objfile *objfile;
+  VEC (stap_entry) *result = NULL;
+  struct cleanup *cleanup, *cleanup_temps;
+  regex_t obj_pat, prov_pat, probe_pat;
+
+  cleanup = make_cleanup (VEC_cleanup (stap_entry), &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, _("Invalid probe regexp"));
+  compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+  ALL_OBJFILES (objfile)
+  {
+    struct stap_probe *probes;
+    int i, num_probes;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	stap_entry entry;
+
+	if (provider)
+	  {
+	    if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	if (probe)
+	  {
+	    if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
+	      continue;
+	  }
+
+	entry.probe = &probes[i];
+	entry.objfile = objfile;
+	VEC_safe_push (stap_entry, result, &entry);
+      }
+  }
+
+  do_cleanups (cleanup_temps);
+  discard_cleanups (cleanup);
+  return result;
+}
+
+/* A qsort comparison function for stap_entry objects.  */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+  const stap_entry *ea = a;
+  const stap_entry *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);
+}
+
+void
+info_probes_stap_command (char *arg, int from_tty)
+{
+  char *provider, *probe = NULL, *objname = NULL;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  VEC (stap_entry) *items;
+  int i, addr_width, any_found;
+  stap_entry *entry;
+
+  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);
+	}
+    }
+
+  items = collect_probes (objname, provider, probe);
+  make_cleanup (VEC_cleanup (stap_entry), &items);
+  make_cleanup_ui_out_table_begin_end (current_uiout, 5,
+				       VEC_length (stap_entry, items),
+				       "SystemTapProbes");
+
+  if (!VEC_empty (stap_entry, items))
+    qsort (VEC_address (stap_entry, items),
+	   VEC_length (stap_entry, items),
+	   sizeof (stap_entry),
+	   compare_entries);
+
+  addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
+
+  ui_out_table_header (current_uiout, 10, ui_left, "provider", _("Provider"));
+  ui_out_table_header (current_uiout, 10, ui_left, "name", _("Name"));
+  ui_out_table_header (current_uiout, addr_width - 1, ui_left, "addr", _("Where"));
+  ui_out_table_header (current_uiout, addr_width - 1, ui_left, "semaphore",
+		       _("Semaphore"));
+  ui_out_table_header (current_uiout, 30, ui_left, "object", _("Object"));
+  ui_out_table_body (current_uiout);
+
+  for (i = 0; VEC_iterate (stap_entry, 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_current_arch (),
+			      entry->probe->address);
+      if (entry->probe->sem_addr == 0)
+	ui_out_field_skip (current_uiout, "semaphore");
+      else
+      ui_out_field_core_addr (current_uiout, "semaphore", get_current_arch (),
+			      entry->probe->sem_addr);
+      ui_out_field_string (current_uiout, "object", entry->objfile->name);
+      ui_out_text (current_uiout, "\n");
+
+      do_cleanups (inner);
+    }
+
+  any_found = !VEC_empty (stap_entry, items);
+  do_cleanups (cleanup);
+
+  if (!any_found)
+    ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+VEC (stap_probe_p) *
+find_probes_in_objfile (struct objfile *objfile,
+			const char *provider,
+			const char *name)
+{
+  struct stap_probe *probes;
+  int i, num_probes;
+  VEC (stap_probe_p) *result = NULL;
+
+  if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+    return NULL;
+
+  probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+  for (i = 0; i < num_probes; ++i)
+    {
+      if (strcmp (probes[i].provider, provider) != 0)
+	continue;
+
+      if (strcmp (probes[i].name, name) != 0)
+	continue;
+
+      VEC_safe_push (stap_probe_p, result, &probes[i]);
+    }
+
+  return result;
+}
+
+/* See definition in stap-probe.h.  */
+
+struct symtabs_and_lines
+parse_stap_probe (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;
+
+  result.sals = NULL;
+  result.nelts = 0;
+
+  arg_start = *argptr;
+
+  /* The caller ensured that this starts with `-p' or `-probe'.  */
+  gdb_assert (arg_start
+	      && ((strncmp (arg_start, "-pstap", 6) == 0
+		   && isspace (arg_start[6]))
+		  || (strncmp (arg_start, "-probe-stap", 11) == 0
+		      && isspace (arg_start[11]))));
+
+  if (strncmp (arg_start, "-pstap", 6) == 0)
+    arg_end = arg_start + 6;
+  else
+    arg_end = arg_start + 11;
+  arg_end = skip_spaces (arg_end);
+
+  if (!*arg_end)
+    error (_("argument to `%s' missing"),
+	   (strncmp (arg_start, "-probe-stap", 11) == 0
+	    ? "-probe-stap" : "-pstap"));
+
+  arg = arg_end;
+  arg_end = skip_to_space (arg_end);
+
+  /* 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)
+      {
+	struct stap_probe *probes;
+	int i, num_probes;
+
+	if (!objfile->sf || !objfile->sf->sym_probe_fns)
+	  continue;
+
+	if (objfile_name
+	    && FILENAME_CMP (objfile->name, objfile_name) != 0
+	    && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+	  continue;
+
+	probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile,
+							     &num_probes);
+	for (i = 0; i < num_probes; ++i)
+	  {
+	    struct symtab_and_line *sal;
+
+	    if (provider && strcmp (probes[i].provider, provider) != 0)
+	      continue;
+
+	    if (strcmp (probes[i].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 = probes[i].address;
+	    sal->explicit_pc = 1;
+	    sal->section = find_pc_overlay (sal->pc);
+	    sal->pspace = pspace;
+	    sal->semaphore = probes[i].sem_addr;
+	  }
+      }
+
+  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;
+}
+
+\f
+
+/* See definition in stap-probe.h.  */
+
+struct stap_probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+  {
+    struct stap_probe *probes;
+    int i, num_probes;
+    stap_entry entry;
+
+    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, &num_probes);
+    for (i = 0; i < num_probes; ++i)
+      {
+	if (probes[i].address == pc)
+	  {
+	    *objfile_out = objfile;
+	    return &probes[i];
+	  }
+      }
+  }
+
+  return NULL;
+}
+
+/* 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 stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL==-1 means "_probe_argc".  */
+  gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
+
+  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)
+    return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
+
+  if (sel >= n_probes)
+    error (_("Invalid probe argument %d -- probe has %d arguments available"),
+	   sel, n_probes);
+
+  return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+								  pc_probe,
+								  frame, 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 stap_probe *pc_probe;
+  int n_probes;
+
+  /* SEL == -1 means "_probe_argc".  */
+  gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
+
+  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."));
+}
+
+/* See the comments in stap-probe.h.  */
+
+void
+stap_semaphore_up (CORE_ADDR sem, struct gdbarch *gdbarch)
+{
+  stap_modify_semaphore (sem, 1, gdbarch);
+}
+
+/* See the comments in stap-probe.h.  */
+
+void
+stap_semaphore_down (CORE_ADDR sem, struct gdbarch *gdbarch)
+{
+  stap_modify_semaphore (sem, 0, gdbarch);
+}
+
+/* Implementation of `$_probe_arg*' set of variables.  */
+
+static const struct internalvar_funcs probe_funcs =
+{
+  compute_probe_arg,
+  compile_probe_arg,
+  NULL
+};
+
+void _initialize_stap_probe (void);
+
+void
+_initialize_stap_probe (void)
+{
+  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);
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..1cad8dc
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,161 @@
+/* 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 "vec.h"
+
+struct stap_args_info;
+struct axs_value;
+struct linespec_result;
+
+/* Main structure which holds information about a SystemTap probe.  */
+
+struct stap_probe
+{
+  /* The provider of this probe.  */
+  const char *provider;
+
+  /* The name of the probe.  */
+  const char *name;
+
+  /* The address where the probe is inserted.  */
+  CORE_ADDR address;
+
+  /* The address of the probe's semaphore, or 0 if this probe does not
+     have an associated semaphore.  */
+  CORE_ADDR sem_addr;
+
+  /* Probe's arguments.  Users should generally not examine this, but
+     should instead extract information about the arguments using the
+     methods provided in sym_probe_fns.  */
+  const char *args;
+
+  /* Probe's arguments after parsing.  This is an opaque structure that
+     will hold information about the arguments pointed by ARGS.  */
+  struct stap_args_info *parsed_args;
+
+  /* gdbarch structure associated with this probe.  */
+  struct gdbarch *gdbarch;
+};
+
+/* 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;
+};
+
+typedef struct stap_probe *stap_probe_p;
+DEF_VEC_P (stap_probe_p);
+
+/* A helper for linespec that decodes a stap probe specification.  It
+   returns a symtabs_and_lines object and updates *ARGPTR or throws an
+   error.  */
+
+extern struct symtabs_and_lines parse_stap_probe (char **argptr,
+						  struct linespec_result *canon);
+
+/* Search OBJFILE for a probe with the given PROVIDER and NAME.
+   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 (stap_probe_p) *find_probes_in_objfile (struct objfile *objfile,
+						   const char *provider,
+						   const char *name);
+
+/* Given a PC, find an associated SystemTap probe.  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 stap_probe *find_probe_by_pc (CORE_ADDR pc,
+					    struct objfile **objfile_out);
+
+/* Given PROBE, returns the number of arguments present in that probe's
+   argument string.  */
+
+extern int stap_get_probe_argument_count (struct stap_probe *probe);
+
+/* Given PARSED_ARGS, frees the space allocated to hold information about
+   the probe's parsed arguments.  */
+
+extern void stap_free_parsed_args (struct stap_args_info *parsed_args);
+
+/* Evaluate the probe's argument N, returning a value corresponding
+   to it.  */
+
+extern struct value *stap_evaluate_probe_argument (struct objfile *objfile,
+						   struct stap_probe *probe,
+						   struct frame_info *frame,
+						   int n);
+
+/* Compile the probe's argument N to agent expression.  */
+
+extern void stap_compile_to_ax (struct objfile *objfile,
+				struct stap_probe *probe,
+				struct agent_expr *expr,
+				struct axs_value *value,
+				int n);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+   evaluates argument N.  If there is no probe at that location, or if
+   the probe does not have enough arguments, this returns NULL.  */
+
+extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
+					       int n);
+
+/* Implementation of the `info probes stap' command.  */
+
+extern void info_probes_stap_command (char *arg, int from_tty);
+
+/* 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.  */
+
+extern void stap_semaphore_up (CORE_ADDR sem, struct gdbarch *gdbarch);
+
+/* Clear a SystemTap semaphore.  SEM is the semaphore's address.  */
+
+extern void stap_semaphore_down (CORE_ADDR sem, struct gdbarch *gdbarch);
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 7024ace..8406105 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -29,6 +29,11 @@ struct objfile;
 struct obj_section;
 struct obstack;
 struct block;
+struct stap_probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
 
 /* Comparison function for symbol look ups.  */
 
@@ -297,6 +302,55 @@ struct quick_symbol_functions
 				int need_fullname);
 };
 
+/* Structure of functions used for SystemTap probe support.  If one of
+   these functions is provided, all must be.  */
+
+struct sym_probe_fns
+{
+  /* If non-NULL, return an array of SystemTap probe objects.  The
+     number of objects is returned in *NUM_PROBES.
+
+     The returned value does not have to be freed and it has lifetime of the
+     OBJFILE.  */
+  struct stap_probe *(*sym_get_probes) (struct objfile *,
+					int *num_probes);
+
+  /* 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.  */
+  int (*sym_get_probe_argument_count) (struct objfile *objfile,
+				       struct stap_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 stap_probe *probe,
+						struct frame_info *frame,
+						int 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 stap_probe *probe,
+			     struct agent_expr *expr,
+			     struct axs_value *value,
+			     int 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 +421,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..8dae087 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->semaphore = 0;
 }
 \f
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d9e5f4a..cb6206d 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1045,6 +1045,10 @@ struct symtab_and_line
   CORE_ADDR end;
   int explicit_pc;
   int explicit_line;
+
+  /* If non-zero, the semaphore location associated with a SystemTap
+     probe.  */
+  CORE_ADDR semaphore;
 };
 
 extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index fac6b44..306c443 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 "stap-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)
+	stap_semaphore_up (loc->semaphore, 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.  */
+	  stap_semaphore_down (loc->semaphore, 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 86ae8fb..288709e 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3112,6 +3112,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] 83+ messages in thread

* [PATCH 4/4 v2] Documentation and testsuite changes
  2012-04-06  3:28 [PATCH 0/4 v2] Implement support for SystemTap probes on userspace Sergio Durigan Junior
  2012-04-06  3:32 ` [PATCH 1/4 v2] Refactor internal variable mechanism Sergio Durigan Junior
  2012-04-06  3:36 ` [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
@ 2012-04-06  3:37 ` Sergio Durigan Junior
  2012-04-06  9:27   ` Eli Zaretskii
  2012-04-06  4:11 ` [PATCH 3/4 v2] Use longjmp and exception probes when available Sergio Durigan Junior
  3 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-06  3:37 UTC (permalink / raw)
  To: gdb-patches

Hi,

This last patch contains documentation and testsuite changes.  I tried
to address all comments that Eli has made in the first version, but I
have to say that I could use another round of review from Eli and Tom.

Do you think it is good as is?

gdb/doc/ChangeLog
2012-07-04  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-07-04  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                    |   89 +++++++++++++++
 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, 599 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 8002429..8d8e421 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3331,6 +3331,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
@@ -4641,6 +4642,59 @@ 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 SystemTap static probe point
+@value{GDBN} supports @code{SDT} probes in the code.  @code{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++ languages.  See
+@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
+for a good reference on how the @code{SDT} probes are implemented.
+
+Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/}) @code{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} @code{SDT} probes
+in your applications.
+
+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{]} @r{[}@var{name}@r{]} @r{[}@var{objfile}@r{]}
+If given, @var{provider} is a regular expression used to select which
+providers to list.  If omitted, probes by all @var{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''
@@ -6656,6 +6710,27 @@ 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{]}@r{[}@var{provider}:@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 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.
+
+@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{-p} 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.
+
 @end table
 
 
@@ -8912,6 +8987,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
@@ -10856,6 +10935,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} varies from 0 to 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..253d9ba
--- /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" "-p user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "-p two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
-- 
1.7.7.6

-- 
Sergio

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH 3/4 v2] Use longjmp and exception probes when available
  2012-04-06  3:28 [PATCH 0/4 v2] Implement support for SystemTap probes on userspace Sergio Durigan Junior
                   ` (2 preceding siblings ...)
  2012-04-06  3:37 ` [PATCH 4/4 v2] Documentation and testsuite changes Sergio Durigan Junior
@ 2012-04-06  4:11 ` Sergio Durigan Junior
  3 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-06  4:11 UTC (permalink / raw)
  To: gdb-patches

Hi,

Just like the patch #1, this patch also didn't change from the last
version, which can be found here:

    http://sourceware.org/ml/gdb-patches/2012-03/msg00356.html

OK to check-in?

gdb/ChangeLog
2012-07-04  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 |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/infrun.c     |   77 ++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 154 insertions(+), 12 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 43d5b29..51c4295 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2740,11 +2740,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 (stap_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 (stap_probe_p) *exception_probes;
 };
 
 static const struct objfile_data *breakpoint_objfile_key;
@@ -2781,6 +2793,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 (stap_probe_p, bp_objfile_data->longjmp_probes);
+  VEC_free (stap_probe_p, bp_objfile_data->exception_probes);
+}
+
+static void
 create_overlay_event_breakpoint (void)
 {
   struct objfile *objfile;
@@ -2857,6 +2878,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 stap_probe *probe;
+	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+	  for (i = 0;
+	       VEC_iterate (stap_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 ("-p libc:longjmp");
+	      b->enable_state = bp_disabled;
+	    }
+
+	  continue;
+	}
+
       for (i = 0; i < NUM_LONGJMP_NAMES; i++)
 	{
 	  struct breakpoint *b;
@@ -2967,6 +3019,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 stap_probe *probe;
+
+	  for (i = 0;
+	       VEC_iterate (stap_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 ("-p libgcc:unwind");
+	      b->enable_state = bp_disabled;
+	    }
+
+	  continue;
+	}
+
+      /* Otherwise, try the hook function.  */
+
       if (msym_not_found_p (bp_objfile_data->exception_msym))
 	continue;
 
@@ -15121,7 +15207,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/infrun.c b/gdb/infrun.c
index 54e39ef..d9bd886 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -55,6 +55,8 @@
 #include "continuations.h"
 #include "interps.h"
 #include "skip.h"
+#include "stap-probe.h"
+#include "objfiles.h"
 
 /* Prototypes for local functions */
 
@@ -2392,7 +2394,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);
@@ -4427,9 +4429,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 = stap_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,
@@ -4447,12 +4457,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;
 
@@ -5539,15 +5544,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 stap_probe *probe,
+				    struct objfile *objfile,
+				    struct frame_info *frame)
+{
+  struct value *arg_value;
+  CORE_ADDR handler;
+  struct breakpoint *bp;
+
+  arg_value = stap_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 stap_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] 83+ messages in thread

* Re: [PATCH 4/4 v2] Documentation and testsuite changes
  2012-04-06  3:37 ` [PATCH 4/4 v2] Documentation and testsuite changes Sergio Durigan Junior
@ 2012-04-06  9:27   ` Eli Zaretskii
  2012-04-09 21:37     ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Eli Zaretskii @ 2012-04-06  9:27 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Fri, 06 Apr 2012 00:37:14 -0300
> 
> This last patch contains documentation and testsuite changes.  I tried
> to address all comments that Eli has made in the first version, but I
> have to say that I could use another round of review from Eli and Tom.

Here's mine.

> +@cindex SystemTap static probe point

Although SystemTap is a proper name, I'd prefer for its index entries
to start with a lowercase letter, because otherwise an Info manual
built in some non-English locale could have the index entries sorted
in surprising ways, since the collation order of uppercase letters
differs from that in en_*.

If you think we must use "SystemTap" literally, how about moving words
around, as in

 @cindex static probe point, SystemTap

> +@value{GDBN} supports @code{SDT} probes in the code.  @code{SDT} stands
> +for Statically Defined Tracing, and the probes are designed to have a tiny

Since you are introducing a new term "SDT", the first time it is used
it should be in @dfn.  Also, instead of @code{SDT}, I would use
@acronym{SDT} everywhere, as it really isn't a symbol in some program,
but an acronym.

> +runtime code and data footprint, and no dynamic relocations.  They are
> +usable from assembly, C and C++ languages.
                               ^^^
We use "C@t{++}" in the manual, it looks better in print.

> +@item info probes stap @r{[}@var{provider}@r{]} @r{[}@var{name}@r{]} @r{[}@var{objfile}@r{]}

I think the brackets should be nested, as you did in NEWS.  I mean,
"name" can only be given if "provider" is given, and "objfile" can be
given only if the other tow are, right?  So each one is not
independently optional.

> +If given, @var{provider} is a regular expression used to select which
> +providers to list.                                    ^^^^^^^^^^^^^^^
   ^^^^^^^^^^^^^^^^^
"to match against provider names when selecting which probes to list".
You don't list providers, you list probes.

> If omitted, probes by all @var{providers} are listed.

Here "providers" is a literal word, so it should not have the @var
markup.

> +@item -pstap|-probe-stap @r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}

Likewise here: the brackets should be nested, I believe.

> +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 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.

Here, you give almost no clue that these parameters can be regular
expressions.  Please rewrite to make that clear, e.g.:

  If @var{objfile} is given, only probes coming from a shared library
  or executable matching @var{objfile} as a regular expression are
  considered.

> +@cindex Semaphores on static probe points

Lower-case "semaphores", please.  Index entries should all start with
a lowercase letter.

> +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{-p} 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.

Why is this here?  Shouldn't it be where static probe points are
described?

> +@item $_probe_arg@var{n}
> +@var{n} varies from 0 to 11.

Not "varies from 0 to 11", but "is an integer between 0 and 11".
There's no variation here, as in case of a variable whose value can
change.

OK with those changes.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/4 v2] Documentation and testsuite changes
  2012-04-06  9:27   ` Eli Zaretskii
@ 2012-04-09 21:37     ` Sergio Durigan Junior
  0 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-09 21:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Friday, April 06 2012, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Date: Fri, 06 Apr 2012 00:37:14 -0300
>> 
>> This last patch contains documentation and testsuite changes.  I tried
>> to address all comments that Eli has made in the first version, but I
>> have to say that I could use another round of review from Eli and Tom.
>
> Here's mine.

Thank you.  I have addressed all the issues you have pointed, and am
sending the reworked patch below.  I will wait until the rest of the
patches is reviewed, then I'll commit this one along with the others.

Thank you for the comments.

-- 
Sergio

gdb/doc/ChangeLog
2012-09-04  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-09-04  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 8002429..59ef223 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3331,6 +3331,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
@@ -4641,6 +4642,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''
@@ -6656,6 +6720,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
 
 
@@ -8912,6 +8989,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
@@ -10856,6 +10937,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..253d9ba
--- /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" "-p user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "-p two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes
  2012-04-06  3:36 ` [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
@ 2012-04-11 19:06   ` Jan Kratochvil
  2012-04-11 22:14     ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2012-04-11 19:06 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Pedro Alves, Tom Tromey, Mark Kettenis

Hi Sergio,

$ gdb /lib64/ld-linux-x86-64.so.2
(gdb) info probes
Provider   Name       Where               Semaphore           Object
 - You have columns widths wrongly computed.
rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib/debug/lib64/ld-2.15.so.debug
rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib64/ld-linux-x86-64.so.2
[...]
 - You do not filter out separate debug info files or rather unify it somehow.


I see you have chosen abstraction (for non-stap probes) purely at the user
level, without abstraction at the GDB API level; if any non-Red Hat
contributor reads this mail what are your opinions?  I do not find great to
spread probe-backend (=stap) specific code across GDB.  breakpoint.c should
include (hypothetical) probe.h, not stap-probe.h.

Also the code like:
          val = bl->owner->ops->insert_location (bl);
+             stap_semaphore_up (bl->semaphore, bl->gdbarch);
suggests stap_semaphore_up should be done by virtualized
bkpt_stap_probe_breakpoint_ops->insert_location without such hack needed in
generic code.  The same applies to:
struct bp_location
+  CORE_ADDR semaphore;
there should be some generic void *user_data; for owner of the
breakpoint_location, when it is all already nicely virtualized by Pedro.

This part was not addressed, I leave it up to Tom, I guess he agrees with it so
OK, the values virtualization is not so great anyway, so fine with that:
# Moreover I would still more see to drop [patch 1/3], call just
# compute_probe_arg which returns lazy lval_computed struct value * which
# provides new struct lval_funcs member which can return `struct expression *'
# and generic code can call gen_expr on its own.  There is no need for special
# internalvar_funcs->compile_to_ax member.
# 
# internalvar_funcs->destroy can be also replaced by lval_funcs->free_closure.


On Fri, 06 Apr 2012 05:35:23 +0200, Sergio Durigan Junior wrote:
> definitions for a new command called `info probes'.  This command can
> take 2 arguments: `stap' and `all'.

'all' not, see in the code.


I was also looking at this code:
insert_exception_resume_from_probe:
  arg_value = stap_safe_evaluate_at_pc (frame, 1);
stap-probe.h:
/* A convenience function that finds a probe at the PC in FRAME and
   evaluates argument N.  If there is no probe at that location, or if
   the probe does not have enough arguments, this returns NULL.  */
extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
                                               int n);

and please describe that N is numbering 0 as the first argument and what is
that argument #1 in insert_exception_resume_from_probe.


> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,12 @@
>  
>  *** Changes since GDB 7.4
>  
> +* GDB now has support for SystemTap <sys/sdt.h> probes.  You can set a
> +  breakpoint using the new "-p" or "-probe" options and inspect the probe

It is called -probe-stap and -pstap.  (Although suggesting in the code
also/instead to provide -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.  
[...]
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
[...]
> @@ -8962,6 +8978,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;
> +
> +  /* Matching breakpoints on SystemTap probes (`-pstap' or `-probe-stap').  */
> +  if (arg && ((strncmp (arg, "-probe-stap", 11) == 0 && isspace (arg[11]))
> +	      || (strncmp (arg, "-pstap", 6) == 0 && isspace (arg[6]))))

These options are not documented in 'help break' at all.

I miss there an option "-probe" which would break on any/all probe kind if
multiple backends exist, that was one of the points of the UI abstraction of
probes.


> +    ops = &bkpt_stap_probe_breakpoint_ops;
> +  else
> +    ops = &bkpt_breakpoint_ops;
>  
>    create_breakpoint (get_current_arch (),
>  		     arg,
[...]
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
[...]
> +static int
> +handle_probe (struct objfile *objfile, struct sdt_note *el,
> +	      struct stap_probe *ret, 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;
> +
> +  ret->gdbarch = gdbarch;
> +
> +  /* Provider and the name of the probe.  */
> +  ret->provider = &el->data[3 * size];
> +  ret->name = memchr (ret->provider, '\0',
> +		      (char *) el->data + el->size - ret->provider);
> +  /* Making sure there is a name.  */
> +  if (!ret->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 0;
> +    }
> +  else
> +    ++ret->name;
> +
> +  /* Retrieving the probe's address.  */
> +  ret->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->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.  */
> +  ret->args = memchr (ret->name, '\0',
> +		      (char *) el->data + el->size - ret->name);

Here if ret->args == NULL you return a valid probe.  But in such case
ret->name is not properly '\0'-terminated and some code like compare_entries
may crash overrunning the memory as it just takes ret->name as a string.
Here if ret->args == NULL I believe you should also do that:
      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 0;

> +
> +  if (ret->args != NULL)
> +    ++ret->args;
> +
> +  if (ret->args == NULL || (memchr (ret->args, '\0',
> +				    (char *) el->data + el->size - ret->name)
> +			    != el->data + el->size - 1))
> +    {
> +      /* Although failing here is not good, it is still possible to use a
> +	 probe without arguments.  That's why we don't return zero.  */
> +      complaint (&symfile_complaints, _("corrupt probe argument when "
> +					"reading `%s'"), objfile->name);
> +      ret->args = NULL;
> +    }
> +
> +  return 1;
> +}
[...]
> +static int
> +get_base_address (bfd *obfd, bfd_vma *base)
> +{
> +  asection *ret = NULL;
> +
> +  bfd_map_over_sections (obfd, get_base_address_1, (void *) &ret);
> +
> +  if (!ret)
> +    {
> +      complaint (&symfile_complaints, _("could not obtain base address for "
> +					"SystemTap section."));

Not a requirement for change but in general please provide more specific
error/warning messages when it is easy to do, it could be said at more points,
such as here with obfd->name, when you load 100+ shared libraries and it
displays
	could not obtain base address for SystemTap section.
one may not be sure which library it was.


> +      return 0;
> +    }
> +
> +  if (base)
> +    *base = ret->vma;
> +
> +  return 1;
> +}
[...]
> --- /dev/null
> +++ b/gdb/probe.c
> @@ -0,0 +1,65 @@
> +/* Generic SDT probe support for GDB.

Not SDT.


> +
> +   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 "command.h"
> +#include "cli/cli-cmds.h"
> +
> +/* Implementation of the `info probes' command.  */
> +
> +static void
> +info_probes_command (char *arg, int from_tty)
> +{
> +  /* If we are here, it means the user has not specified any
> +     argument, or has specified `all'.  In either case, we should
> +     print information about all types of probes.  */
> +  info_probes_stap_command (arg, from_tty);
> +}
> +
> +void _initialize_probe (void);
> +
> +void
> +_initialize_probe (void)
> +{
> +  static struct cmd_list_element *info_probes_cmdlist;
> +
> +  add_prefix_cmd ("probes", class_info, info_probes_command,
> +		  _("\
> +Show available static probes.\n\
> +Usage: info probes [all|TYPE [ARGS]]\n\

"info probes all" does not work.  "info probes" works correctly.

I do not think there is any "all" needed, just fix documentation that for all
kinds of probes one should type "info probes" and that's all, isn't it?


> +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);
> +
> +  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);
> +}
[...]
> --- /dev/null
> +++ b/gdb/stap-probe.c
[...]
> +static void
> +stap_parse_probe_arguments (struct stap_probe *probe)
> +{
> +  struct stap_args_info *args_info;
> +  struct cleanup *back_to;
> +  const char *cur = probe->args;
> +  int current_arg = -1;
> +
> +  /* This is a state-machine parser, which means we will always be
> +     in a known state when parsing an argument.  The state could be
> +     either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
> +     we are parsing the bitness-definition part (i.e., `4@'), or
> +     `PARSE_ARG' if we are actually parsing the argument part.  */
> +  enum
> +    {
> +      NEW_ARG,
> +      BITNESS,
> +      PARSE_ARG,
> +    } current_state;
> +
> +  /* For now, we assume everything is not going to work.  */
> +  probe->parsed_args = &dummy_stap_args_info;

I did not check if it is a regression due to stap_parse_argument throws an
exception now or not or if it is even intentional but I do not find it OK:

(gdb) file gdb.base/stap-probe
(gdb) break -pstap test:user
(gdb) run
(gdb) print $_probe_argc
stap_parse_argument: <-4(%rbp)>
Cannot parse expression `foo'.
(gdb) print $_probe_argc
$1 = 0

IMO it should give an error in each case, shouldn't it?


> +
> +  if (!cur || !*cur || *cur == ':')
> +    return;
> +
> +  args_info = xmalloc (sizeof (struct stap_args_info));
> +  args_info->n_args = 0;
> +  back_to = make_cleanup (stap_free_args_info, args_info);
> +  args_info->args = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
> +
> +  current_state = NEW_ARG;

Otherwise I am fine with the patch.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes
  2012-04-11 19:06   ` Jan Kratochvil
@ 2012-04-11 22:14     ` Sergio Durigan Junior
  2012-04-11 23:33       ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-04-11 22:14 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, Pedro Alves, Tom Tromey, Mark Kettenis

Thanks for the review.

On Wednesday, April 11 2012, Jan Kratochvil wrote:

> Hi Sergio,
>
> $ gdb /lib64/ld-linux-x86-64.so.2
> (gdb) info probes
> Provider   Name       Where               Semaphore           Object
>  - You have columns widths wrongly computed.

Thanks, I'll fix it.

> rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib/debug/lib64/ld-2.15.so.debug
> rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib64/ld-linux-x86-64.so.2
> [...]
>  - You do not filter out separate debug info files or rather unify it
> somehow.

`info probes stap' accept an argument specifying the provider, name and
objfile of the probe, so I guess this is the filter you're talking about.

> I see you have chosen abstraction (for non-stap probes) purely at the user
> level, without abstraction at the GDB API level; if any non-Red Hat
> contributor reads this mail what are your opinions?  I do not find great to
> spread probe-backend (=stap) specific code across GDB.  breakpoint.c should
> include (hypothetical) probe.h, not stap-probe.h.

As we have discussed, I will now try to implement this abstraction in a
proper way.  Meanwhile, I believe this patch is on-hold and probably not
valid for further reviews.

> On Fri, 06 Apr 2012 05:35:23 +0200, Sergio Durigan Junior wrote:
>> definitions for a new command called `info probes'.  This command can
>> take 2 arguments: `stap' and `all'.
>
> 'all' not, see in the code.

Thanks, I'll fix it.

> I was also looking at this code:
> insert_exception_resume_from_probe:
>   arg_value = stap_safe_evaluate_at_pc (frame, 1);
> stap-probe.h:
> /* A convenience function that finds a probe at the PC in FRAME and
>    evaluates argument N.  If there is no probe at that location, or if
>    the probe does not have enough arguments, this returns NULL.  */
> extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
>                                                int n);
>
> and please describe that N is numbering 0 as the first argument and what is
> that argument #1 in insert_exception_resume_from_probe.
>
>
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -3,6 +3,12 @@
>>  
>>  *** Changes since GDB 7.4
>>  
>> +* GDB now has support for SystemTap <sys/sdt.h> probes.  You can set a
>> +  breakpoint using the new "-p" or "-probe" options and inspect the probe
>
> It is called -probe-stap and -pstap.  (Although suggesting in the code
> also/instead to provide -probe.)

Fixed.  I will still add the `-probe' option.

>> --- a/gdb/breakpoint.c
>> +++ b/gdb/breakpoint.c
> [...]
>> @@ -8962,6 +8978,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;
>> +
>> +  /* Matching breakpoints on SystemTap probes (`-pstap' or `-probe-stap').  */
>> +  if (arg && ((strncmp (arg, "-probe-stap", 11) == 0 && isspace (arg[11]))
>> +	      || (strncmp (arg, "-pstap", 6) == 0 && isspace (arg[6]))))
>
> These options are not documented in 'help break' at all.
>
> I miss there an option "-probe" which would break on any/all probe kind if
> multiple backends exist, that was one of the points of the UI abstraction of
> probes.

Ok, I will work on this.

>> --- a/gdb/elfread.c
>> +++ b/gdb/elfread.c
> [...]
>> +static int
>> +handle_probe (struct objfile *objfile, struct sdt_note *el,
>> +	      struct stap_probe *ret, 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;
>> +
>> +  ret->gdbarch = gdbarch;
>> +
>> +  /* Provider and the name of the probe.  */
>> +  ret->provider = &el->data[3 * size];
>> +  ret->name = memchr (ret->provider, '\0',
>> +		      (char *) el->data + el->size - ret->provider);
>> +  /* Making sure there is a name.  */
>> +  if (!ret->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 0;
>> +    }
>> +  else
>> +    ++ret->name;
>> +
>> +  /* Retrieving the probe's address.  */
>> +  ret->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->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.  */
>> +  ret->args = memchr (ret->name, '\0',
>> +		      (char *) el->data + el->size - ret->name);
>
> Here if ret->args == NULL you return a valid probe.  But in such case
> ret->name is not properly '\0'-terminated and some code like compare_entries
> may crash overrunning the memory as it just takes ret->name as a string.
> Here if ret->args == NULL I believe you should also do that:
>       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 0;

Ok, fixed as you recommended.

>> +
>> +  if (ret->args != NULL)
>> +    ++ret->args;
>> +
>> +  if (ret->args == NULL || (memchr (ret->args, '\0',
>> +				    (char *) el->data + el->size - ret->name)
>> +			    != el->data + el->size - 1))
>> +    {
>> +      /* Although failing here is not good, it is still possible to use a
>> +	 probe without arguments.  That's why we don't return zero.  */
>> +      complaint (&symfile_complaints, _("corrupt probe argument when "
>> +					"reading `%s'"), objfile->name);
>> +      ret->args = NULL;
>> +    }
>> +
>> +  return 1;
>> +}
> [...]
>> +static int
>> +get_base_address (bfd *obfd, bfd_vma *base)
>> +{
>> +  asection *ret = NULL;
>> +
>> +  bfd_map_over_sections (obfd, get_base_address_1, (void *) &ret);
>> +
>> +  if (!ret)
>> +    {
>> +      complaint (&symfile_complaints, _("could not obtain base address for "
>> +					"SystemTap section."));
>
> Not a requirement for change but in general please provide more specific
> error/warning messages when it is easy to do, it could be said at more points,
> such as here with obfd->name, when you load 100+ shared libraries and it
> displays
> 	could not obtain base address for SystemTap section.
> one may not be sure which library it was.

Ok.

>
>
>> +      return 0;
>> +    }
>> +
>> +  if (base)
>> +    *base = ret->vma;
>> +
>> +  return 1;
>> +}
> [...]
>> --- /dev/null
>> +++ b/gdb/probe.c
>> @@ -0,0 +1,65 @@
>> +/* Generic SDT probe support for GDB.
>
> Not SDT.

SDT stands for Statically Defined Probe, so I think SDT is correct in
this case.  Don't you?

>> +
>> +   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 "command.h"
>> +#include "cli/cli-cmds.h"
>> +
>> +/* Implementation of the `info probes' command.  */
>> +
>> +static void
>> +info_probes_command (char *arg, int from_tty)
>> +{
>> +  /* If we are here, it means the user has not specified any
>> +     argument, or has specified `all'.  In either case, we should
>> +     print information about all types of probes.  */
>> +  info_probes_stap_command (arg, from_tty);
>> +}
>> +
>> +void _initialize_probe (void);
>> +
>> +void
>> +_initialize_probe (void)
>> +{
>> +  static struct cmd_list_element *info_probes_cmdlist;
>> +
>> +  add_prefix_cmd ("probes", class_info, info_probes_command,
>> +		  _("\
>> +Show available static probes.\n\
>> +Usage: info probes [all|TYPE [ARGS]]\n\
>
> "info probes all" does not work.  "info probes" works correctly.
>
> I do not think there is any "all" needed, just fix documentation that for all
> kinds of probes one should type "info probes" and that's all, isn't
> it?

I don't have a strong opinion about it, so yeah, we could use only
`info probes'.

>> +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);
>> +
>> +  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);
>> +}
> [...]
>> --- /dev/null
>> +++ b/gdb/stap-probe.c
> [...]
>> +static void
>> +stap_parse_probe_arguments (struct stap_probe *probe)
>> +{
>> +  struct stap_args_info *args_info;
>> +  struct cleanup *back_to;
>> +  const char *cur = probe->args;
>> +  int current_arg = -1;
>> +
>> +  /* This is a state-machine parser, which means we will always be
>> +     in a known state when parsing an argument.  The state could be
>> +     either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
>> +     we are parsing the bitness-definition part (i.e., `4@'), or
>> +     `PARSE_ARG' if we are actually parsing the argument part.  */
>> +  enum
>> +    {
>> +      NEW_ARG,
>> +      BITNESS,
>> +      PARSE_ARG,
>> +    } current_state;
>> +
>> +  /* For now, we assume everything is not going to work.  */
>> +  probe->parsed_args = &dummy_stap_args_info;
>
> I did not check if it is a regression due to stap_parse_argument throws an
> exception now or not or if it is even intentional but I do not find it OK:
>
> (gdb) file gdb.base/stap-probe
> (gdb) break -pstap test:user
> (gdb) run
> (gdb) print $_probe_argc
> stap_parse_argument: <-4(%rbp)>
> Cannot parse expression `foo'.
> (gdb) print $_probe_argc
> $1 = 0
>
> IMO it should give an error in each case, shouldn't it?

I am taking a look, it should give a better error message.

>> +
>> +  if (!cur || !*cur || *cur == ':')
>> +    return;
>> +
>> +  args_info = xmalloc (sizeof (struct stap_args_info));
>> +  args_info->n_args = 0;
>> +  back_to = make_cleanup (stap_free_args_info, args_info);
>> +  args_info->args = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
>> +
>> +  current_state = NEW_ARG;
>
> Otherwise I am fine with the patch.
>
>
> Thanks,
> Jan

-- 
Sergio

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes
  2012-04-11 22:14     ` Sergio Durigan Junior
@ 2012-04-11 23:33       ` Jan Kratochvil
  0 siblings, 0 replies; 83+ messages in thread
From: Jan Kratochvil @ 2012-04-11 23:33 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches, Pedro Alves, Tom Tromey, Mark Kettenis

On Wed, 11 Apr 2012 23:33:18 +0200, Sergio Durigan Junior wrote:
> On Wednesday, April 11 2012, Jan Kratochvil wrote:
> > rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib/debug/lib64/ld-2.15.so.debug
> > rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib64/ld-linux-x86-64.so.2
> > [...]
> >  - You do not filter out separate debug info files or rather unify it
> > somehow.
> 
> `info probes stap' accept an argument specifying the provider, name and
> objfile of the probe, so I guess this is the filter you're talking about.

Really not, the main binary and its separate debug info file represent single
object.  You can see the address is the same, it is the same probe.  There is
no reason why to display it twice.  There are already (too) many exceptions in
GDB codebase to ignore this or that if a separate debug info file exists.


> >> +++ b/gdb/probe.c
> >> @@ -0,0 +1,65 @@
> >> +/* Generic SDT probe support for GDB.
> >
> > Not SDT.
> 
> SDT stands for Statically Defined Probe, so I think SDT is correct in
> this case.  Don't you?

"SDT stands for Statically Defined Tracing" and I believe SDT is bound to
DTrace (and therefore also SystemTap) but feel free to write anything there,
I thought it is a typo/thinko.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2011-04-19 16:42 ` Jan Kratochvil
@ 2012-05-07 19:36   ` Jan Kratochvil
  2012-05-07 19:54     ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2012-05-07 19:36 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

Hi Sergio,

I have found I have asked three times on this list (IIRC even elsewhere) to
fix this debuginfo probes bug and in the end it got checked in with this bug
anyway.  Could you fix it, please?


Thanks,
Jan


On Tue, 19 Apr 2011 18:42:41 +0200, Jan Kratochvil wrote:
> there is still the bug as present on Fedora 15 with:
> 	glibc-2.13.90-9.x86_64
> 	glibc-debuginfo-2.13.90-9.x86_64
> 
> (gdb) info probes 
> Provider   Name       Where               Semaphore           Object                         
> libc       lll_futex_wake 0x00007ffff61a5f7b                      /lib64/libc.so.6               
> libc       lll_futex_wake 0x00007ffff61a5f7b                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
> libc       lll_futex_wake 0x00007ffff6213060                      /lib64/libc.so.6               
> libc       lll_futex_wake 0x00007ffff6213060                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
> libc       lll_lock_wait_private 0x00007ffff61e5a84                      /lib64/libc.so.6               
> libc       lll_lock_wait_private 0x00007ffff61e5a84                      /usr/lib/debug/lib64/libc-2.13.90.so.debug 
> [...]
> 
> That is everything is duplicate for the separate debug info files.
+
On Fri, 04 Nov 2011 17:26:48 +0100, Jan Kratochvil wrote:
> Also I think you should discard the separate debug info objfiles.  I find
> wrong to display:
>         0x37aa200000       0x37aa222000    0x22000 /usr/lib/debug/lib64/ld-2.14.90.so.debug
> when it in fact means:
>         0x37aa200000       0x37aa222000    0x22000 /lib64/ld-2.14.90.so
+
On Wed, 11 Apr 2012 20:42:33 +0200, Jan Kratochvil wrote:
> $ gdb /lib64/ld-linux-x86-64.so.2
> (gdb) info probes
> Provider   Name       Where               Semaphore           Object
>  - You have columns widths wrongly computed.
> rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib/debug/lib64/ld-2.15.so.debug
> rtld       lll_futex_wake 0x000000000000ab2e                      /usr/lib64/ld-linux-x86-64.so.2
> [...]
>  - You do not filter out separate debug info files or rather unify it somehow.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2012-05-07 19:36   ` Jan Kratochvil
@ 2012-05-07 19:54     ` Sergio Durigan Junior
  2012-05-07 19:58       ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-05-07 19:54 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Monday, May 07 2012, Jan Kratochvil wrote:

> I have found I have asked three times on this list (IIRC even elsewhere) to
> fix this debuginfo probes bug and in the end it got checked in with this bug
> anyway.  Could you fix it, please?

You are right, I am sorry.  I was sure I had fixed the bug, but now I
see that I actually hacked the wrong function.  Does this patch work for
you?

Thanks,

-- 
Sergio

2012-05-07  Sergio Durigan Junior  <sergiodj@redhat.com>

	* probe.c (collect_probes): Filtering debuginfo object files.

diff --git a/gdb/probe.c b/gdb/probe.c
index ee94f9c..832e57c 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -303,6 +303,9 @@ collect_probes (char *objname, char *provider, char *probe_name,
       if (! objfile->sf || ! objfile->sf->sym_probe_fns)
 	continue;
 
+      if (objfile->separate_debug_objfile_backlink != NULL)
+	continue;
+
       if (objname)
 	{
 	  if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2012-05-07 19:54     ` Sergio Durigan Junior
@ 2012-05-07 19:58       ` Jan Kratochvil
  2012-05-07 20:26         ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2012-05-07 19:58 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Mon, 07 May 2012 21:53:49 +0200, Sergio Durigan Junior wrote:
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -303,6 +303,9 @@ collect_probes (char *objname, char *provider, char *probe_name,
>        if (! objfile->sf || ! objfile->sf->sym_probe_fns)
>  	continue;
>  
> +      if (objfile->separate_debug_objfile_backlink != NULL)
> +	continue;
> +

I do not think it should be kind-unspecific.  Different probe kind can be for
example present only in .debug files and not in the main binaries.

Also I do not find great that it does not get displayed by `info probes' but
other commands still process even probes from .debug files.

Couldn't you put this conditional rather into stap_get_probes?


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2012-05-07 19:58       ` Jan Kratochvil
@ 2012-05-07 20:26         ` Sergio Durigan Junior
  2012-05-07 20:38           ` Jan Kratochvil
  0 siblings, 1 reply; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-05-07 20:26 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Monday, May 07 2012, Jan Kratochvil wrote:

> On Mon, 07 May 2012 21:53:49 +0200, Sergio Durigan Junior wrote:
>> --- a/gdb/probe.c
>> +++ b/gdb/probe.c
>> @@ -303,6 +303,9 @@ collect_probes (char *objname, char *provider, char *probe_name,
>>        if (! objfile->sf || ! objfile->sf->sym_probe_fns)
>>  	continue;
>>  
>> +      if (objfile->separate_debug_objfile_backlink != NULL)
>> +	continue;
>> +
>
> I do not think it should be kind-unspecific.  Different probe kind can be for
> example present only in .debug files and not in the main binaries.
>
> Also I do not find great that it does not get displayed by `info probes' but
> other commands still process even probes from .debug files.
>
> Couldn't you put this conditional rather into stap_get_probes?

Here it is.  I also removed a previous conditional that I had put in
probes.c:parse_probes, because it is not needed at all.

OK to apply?

-- 
Sergio

2012-05-07  Sergio Duriga Junior  <sergiodj@redhat.com>

	* probe.c (parse_probes): Move conditional to check for
	debuginfo objfiles to...
	* stap-probe.c (stap_get_probes): ...here.

diff --git a/gdb/probe.c b/gdb/probe.c
index ee94f9c..77f3b13 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -120,9 +120,6 @@ parse_probes (char **argptr, struct linespec_result *canonical)
 	    && 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++)
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 273ae07..506e6c3 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1411,6 +1411,12 @@ stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
   struct sdt_note *iter;
   unsigned save_probesp_len = VEC_length (probe_p, *probesp);
 
+  if (objfile->separate_debug_objfile_backlink != NULL)
+    {
+      /* This is a .debug file, not the objfile itself.  */
+      return;
+    }
+
   if (!elf_tdata (obfd)->sdt_note_head)
     {
       /* There isn't any probe here.  */

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2012-05-07 20:26         ` Sergio Durigan Junior
@ 2012-05-07 20:38           ` Jan Kratochvil
  2012-05-08  1:36             ` Sergio Durigan Junior
  0 siblings, 1 reply; 83+ messages in thread
From: Jan Kratochvil @ 2012-05-07 20:38 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches

On Mon, 07 May 2012 22:25:54 +0200, Sergio Durigan Junior wrote:
> Here it is.  I also removed a previous conditional that I had put in
> probes.c:parse_probes, because it is not needed at all.

OK, I see, sym_get_probes gets called unconditionally from more places.


> 	* probe.c (parse_probes): Move conditional to check for
> 	debuginfo objfiles to...
> 	* stap-probe.c (stap_get_probes): ...here.
[...]
> OK to apply?

Yes.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 4/6] Implement support for SystemTap probes
  2012-05-07 20:38           ` Jan Kratochvil
@ 2012-05-08  1:36             ` Sergio Durigan Junior
  0 siblings, 0 replies; 83+ messages in thread
From: Sergio Durigan Junior @ 2012-05-08  1:36 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Monday, May 07 2012, Jan Kratochvil wrote:

> On Mon, 07 May 2012 22:25:54 +0200, Sergio Durigan Junior wrote:
>> OK to apply?
>
> Yes.

Thanks, checked in:

    http://sourceware.org/ml/gdb-cvs/2012-05/msg00048.html

-- 
Sergio

^ permalink raw reply	[flat|nested] 83+ messages in thread

end of thread, other threads:[~2012-05-08  1:36 UTC | newest]

Thread overview: 83+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-26 21:08 [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
2011-10-26 21:25 ` Sergio Durigan Junior
2011-10-27  7:30   ` Eli Zaretskii
2011-10-27 18:09     ` Sergio Durigan Junior
2011-10-29 19:48       ` Eli Zaretskii
2011-10-31  0:34 ` Jan Kratochvil
2011-10-31  7:00   ` Sergio Durigan Junior
2011-10-31  8:13     ` Jan Kratochvil
2011-10-31 12:57       ` Pedro Alves
2011-11-01 11:54         ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Jan Kratochvil
2011-11-01 16:23           ` Eli Zaretskii
2011-11-03 14:12             ` [patch] `info proc *' help fix [Re: [patch] `info proc ' completion] Jan Kratochvil
2011-11-03 16:57               ` Eli Zaretskii
2011-11-03 17:07                 ` Jan Kratochvil
2011-11-03 18:08                   ` Eli Zaretskii
2011-11-03 18:25                     ` Jan Kratochvil
2011-11-02 18:30           ` [patch] `info proc ' completion [Re: [PATCH] Implement new `info core mappings' command] Pedro Alves
2011-11-02 18:48             ` [commit] " Jan Kratochvil
2011-11-03 20:01       ` [PATCH] Implement new `info core mappings' command Sergio Durigan Junior
2011-11-04 10:38         ` Eli Zaretskii
2011-11-04 16:27         ` Jan Kratochvil
2011-11-08  1:49           ` Sergio Durigan Junior
2011-11-08 21:47             ` Jan Kratochvil
2011-11-09 20:32             ` Jan Kratochvil
2011-11-16  4:10               ` Sergio Durigan Junior
2011-11-21 16:15                 ` Sergio Durigan Junior
2011-11-23 16:32                   ` [rfc] Options for "info mappings" etc. (Re: [PATCH] Implement new `info core mappings' command) Ulrich Weigand
2011-11-23 23:37                     ` Sergio Durigan Junior
2011-12-01 19:51                       ` Ulrich Weigand
2011-12-05 12:59                     ` Pedro Alves
2011-12-05 15:02                       ` Ulrich Weigand
2011-12-06 16:01                         ` Pedro Alves
2011-12-06 17:19                           ` Ulrich Weigand
2011-12-07 16:29                             ` Pedro Alves
2011-12-07 17:24                               ` Pedro Alves
2011-12-07 20:14                               ` Ulrich Weigand
2011-12-09 13:28                                 ` Pedro Alves
2011-12-09 14:10                                   ` Pedro Alves
2011-12-20 23:08                                 ` Ulrich Weigand
2011-12-21 22:36                                   ` Jan Kratochvil
2011-12-22 16:15                                     ` Ulrich Weigand
2012-01-05 16:02                                   ` Pedro Alves
2012-01-05 18:03                                     ` Ulrich Weigand
2012-01-05 18:20                                       ` Pedro Alves
2012-01-05 19:54                                         ` Ulrich Weigand
2012-01-06  6:41                                           ` Joel Brobecker
2012-01-06 12:29                                             ` Pedro Alves
2012-01-06 12:27                                           ` Pedro Alves
2012-01-09 15:44                                             ` Ulrich Weigand
2012-01-11 16:38                                               ` Pedro Alves
2012-01-11 18:32                                                 ` Ulrich Weigand
2012-01-05 18:37                                       ` Mark Kettenis
2012-01-05 19:35                                         ` Ulrich Weigand
  -- strict thread matches above, loose matches on Subject: below --
2012-04-06  3:28 [PATCH 0/4 v2] Implement support for SystemTap probes on userspace Sergio Durigan Junior
2012-04-06  3:32 ` [PATCH 1/4 v2] Refactor internal variable mechanism Sergio Durigan Junior
2012-04-06  3:36 ` [PATCH 2/4 v2] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
2012-04-11 19:06   ` Jan Kratochvil
2012-04-11 22:14     ` Sergio Durigan Junior
2012-04-11 23:33       ` Jan Kratochvil
2012-04-06  3:37 ` [PATCH 4/4 v2] Documentation and testsuite changes Sergio Durigan Junior
2012-04-06  9:27   ` Eli Zaretskii
2012-04-09 21:37     ` Sergio Durigan Junior
2012-04-06  4:11 ` [PATCH 3/4 v2] Use longjmp and exception probes when available Sergio Durigan Junior
2011-04-04  3:09 [PATCH 4/6] Implement support for SystemTap probes Sergio Durigan Junior
2011-04-04 19:06 ` Eli Zaretskii
2011-04-06 20:20 ` Tom Tromey
2011-04-06 20:52   ` Sergio Durigan Junior
2011-04-07  2:41 ` Yao Qi
2011-04-07  3:32   ` Sergio Durigan Junior
2011-04-07 17:04   ` Tom Tromey
2011-04-11  3:21     ` Yao Qi
2011-04-08 12:38   ` Sergio Durigan Junior
2011-04-11  3:52     ` Yao Qi
2011-08-12 15:45     ` Jan Kratochvil
2011-08-12 17:22       ` Frank Ch. Eigler
2011-08-12 21:33         ` Sergio Durigan Junior
2011-04-19 16:42 ` Jan Kratochvil
2012-05-07 19:36   ` Jan Kratochvil
2012-05-07 19:54     ` Sergio Durigan Junior
2012-05-07 19:58       ` Jan Kratochvil
2012-05-07 20:26         ` Sergio Durigan Junior
2012-05-07 20:38           ` Jan Kratochvil
2012-05-08  1:36             ` 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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).