public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH V4 8/9] Documentation for DTrace USDT probes.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (3 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-02 16:03   ` Eli Zaretskii
  2015-02-02 10:57 ` [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch modifies the `Static Probe Points' section on the GDB
manual in order to cover the support for DTrace USDT probes, in
addition to SystemTap SDT probes.

gdb/doc/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* gdb.texinfo (Static Probe Points): Add cindex `static probe
	point, DTrace'.
	(Static Probe Points): Modified to cover DTrace probes in addition
	to SystemTap probes.  Also modified to cover the `enable probe'
	and `disable probe' commands.
---
 gdb/doc/ChangeLog   |    8 +++++++
 gdb/doc/gdb.texinfo |   58 ++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4ab0bba..53fd04b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4967,34 +4967,50 @@ that can no longer be recreated.
 @subsection Static Probe Points
 
 @cindex static probe point, SystemTap
+@cindex static probe point, DTrace
 @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.
+runtime code and data footprint, and no dynamic relocations.
+
+Currently, the following types of probes are supported on
+ELF-compatible systems:
+
+@itemize @bullet
 
-Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
-@acronym{SDT} probes are supported on ELF-compatible systems.  See
+@item @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
+@acronym{SDT} probes@footnote{See
 @uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
-for more information on how to add @code{SystemTap} @acronym{SDT} probes
-in your applications.
+for more information on how to add @code{SystemTap} @acronym{SDT}
+probes in your applications.}.  @code{SystemTap} probes are usable
+from assembly, C and C@t{++} languages@footnote{See
+@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
+for a good reference on how the @acronym{SDT} probes are implemented.}.  
+
+@item @code{DTrace} (@uref{http://oss.oracle.com/projects/DTrace})
+@acronym{USDT} probes.  @code{DTrace} probes are usable from C and
+C@t{++} languages.
+@end itemize
 
 @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.
+Some @code{SystemTap} 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.  @code{DTrace} probes do not support semaphores.
 
 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{]}
+@item info probes @r{[}@var{type}@r{]} @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+If given, @var{type} is either @code{stap} for listing
+@code{SystemTap} probes or @code{dtrace} for listing @code{DTrace}
+probes.  If omitted all probes are listed regardless of their types.
+
 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.
@@ -5014,7 +5030,8 @@ List the available static probes, from all types.
 @cindex enabling and disabling probes
 Some probe points can be enabled and/or disabled.  The effect of
 enabling or disabling a probe depends on the type of probe being
-handled.  @code{SystemTap} probes cannot be disabled.
+handled.  Some @code{DTrace} probes can be enabled or
+disabled, but @code{SystemTap} probes cannot be disabled.
 
 You can enable (or disable) one or more probes using the following
 commands, with optional arguments:
@@ -5045,8 +5062,11 @@ 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
+@code{$_probe_arg0}@dots{}@code{$_probe_arg11}.  In @code{SystemTap}
+probes each probe argument is an integer of the appropriate size;
+types are not preserved.  In @code{DTrace} probes types are preserved
+provided that they are recognized as such by @value{GDBN}; otherwise
+the value of the probe argument will be a long integer.  The
 convenience variable @code{$_probe_argc} holds the number of arguments
 at the current probe point.
 
-- 
1.7.10.4

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

* [PATCH V4 7/9] Simple testsuite for DTrace USDT probes.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
  2015-02-02 10:57 ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
  2015-02-02 10:57 ` [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-02 11:18   ` Jose E. Marchesi
  2015-02-17  1:53   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch adds some simple tests testing the support for DTrace USDT
probes.  The testsuite will be skipped as unsupported in case the user
does not have DTrace installed on her system.  The tests included in the
test suite test breakpointing on DTrace probes, enabling and disabling
probes, printing of probe arguments of several types and also
breakpointing on several probes with the same name.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* Makefile.in (aclocal_m4_deps): Added transform.m4.
	* acinclude.m4: sinclude transform.m4.
	* transform.m4 (GDB_AC_TRANSFORM): New macro.
	New file.
	* configure.ac: Use GDB_AC_TRANSFORM.

gdb/testsuite/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* lib/dtrace.exp: New file.
	* gdb.base/dtrace-probe.exp: Likewise.
	* gdb.base/dtrace-probe.d: Likewise.
	* gdb.base/dtrace-probe.c: Likewise.
	* lib/pdtrace.in: Likewise.
	* configure.ac: Output variables with the transformed names of
	the strip, readelf, as and nm tools.  AC_SUBST lib/pdtrace.in.
	* configure: Regenerated.
	* aclocal.m4: sinclude ../transform.m4.
---
 gdb/ChangeLog                           |    8 +
 gdb/Makefile.in                         |    1 +
 gdb/acinclude.m4                        |    3 +
 gdb/configure                           |   24 +-
 gdb/configure.ac                        |   14 +-
 gdb/testsuite/ChangeLog                 |   12 +
 gdb/testsuite/aclocal.m4                |    1 +
 gdb/testsuite/configure                 |   62 ++
 gdb/testsuite/configure.ac              |    9 +
 gdb/testsuite/gdb.base/dtrace-probe.c   |   38 ++
 gdb/testsuite/gdb.base/dtrace-probe.d   |   21 +
 gdb/testsuite/gdb.base/dtrace-probe.exp |  106 ++++
 gdb/testsuite/lib/dtrace.exp            |   71 +++
 gdb/testsuite/lib/pdtrace.in            | 1033 +++++++++++++++++++++++++++++++
 14 files changed, 1381 insertions(+), 22 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
 create mode 100644 gdb/testsuite/lib/dtrace.exp
 create mode 100755 gdb/testsuite/lib/pdtrace.in

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e933b45..c376f44 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1527,6 +1527,7 @@ aclocal_m4_deps = \
 	configure.ac \
 	acx_configure_dir.m4 \
 	libmcheck.m4 \
+	transform.m4 \
 	../bfd/bfd.m4 \
 	../config/acinclude.m4 \
 	../config/plugins.m4 \
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 6f71486..1f0b574 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -9,6 +9,9 @@ sinclude(acx_configure_dir.m4)
 # This gets GDB_AC_LIBMCHECK.
 sinclude(libmcheck.m4)
 
+# This gets GDB_AC_TRANSFORM.
+sinclude(transform.m4)
+
 dnl gdb/configure.in uses BFD_NEED_DECLARATION, so get its definition.
 sinclude(../bfd/bfd.m4)
 
diff --git a/gdb/configure b/gdb/configure
index 30a54d2..bb9697d 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -15141,17 +15141,21 @@ ac_config_links="$ac_config_links $ac_config_links_1"
 $as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
 
 
-# Undo the $ec_script escaping suitable for Makefile.
-transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
-GDB_TRANSFORM_NAME=`echo gdb | sed -e "$transform"`
-if test "x$GDB_TRANSFORM_NAME" = x; then
-  GDB_TRANSFORM_NAME=gdb
-fi
 
-GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$transform"`
-if test "x$GCORE_TRANSFORM_NAME" = x; then
-  GCORE_TRANSFORM_NAME=gcore
-fi
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  GDB_TRANSFORM_NAME=`echo gdb | sed -e "$gdb_ac_transform"`
+  if test "x$GDB_TRANSFORM_NAME" = x; then
+     GDB_TRANSFORM_NAME=gdb
+  fi
+
+
+
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$gdb_ac_transform"`
+  if test "x$GCORE_TRANSFORM_NAME" = x; then
+     GCORE_TRANSFORM_NAME=gcore
+  fi
+
 
 ac_config_files="$ac_config_files gcore"
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 39fcef2..90bf71c 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2444,18 +2444,8 @@ dnl  At the moment, we just assume it's UTF-8.
 AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8",
           [Define to be a string naming the default host character set.])
 
-# Undo the $ec_script escaping suitable for Makefile.
-transform=`echo "$program_transform_name" | sed -e 's/[\\$][\\$]/\\$/g'`
-GDB_TRANSFORM_NAME=`echo gdb | sed -e "$transform"`
-if test "x$GDB_TRANSFORM_NAME" = x; then
-  GDB_TRANSFORM_NAME=gdb
-fi
-AC_SUBST(GDB_TRANSFORM_NAME)
-GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$transform"`
-if test "x$GCORE_TRANSFORM_NAME" = x; then
-  GCORE_TRANSFORM_NAME=gcore
-fi
-AC_SUBST(GCORE_TRANSFORM_NAME)
+GDB_AC_TRANSFORM([gdb], [GDB_TRANSFORM_NAME])
+GDB_AC_TRANSFORM([gcore], [GCORE_TRANSFORM_NAME])
 AC_CONFIG_FILES([gcore], [chmod +x gcore])
 
 AC_OUTPUT(Makefile gdb-gdb.gdb doc/Makefile data-directory/Makefile,
diff --git a/gdb/testsuite/aclocal.m4 b/gdb/testsuite/aclocal.m4
index 2934db2..d40c3a9 100644
--- a/gdb/testsuite/aclocal.m4
+++ b/gdb/testsuite/aclocal.m4
@@ -1,5 +1,6 @@
 sinclude(../../config/acx.m4)
 sinclude(../../config/override.m4)
+sinclude(../transform.m4)
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index ca033c3..f36a1bd 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -591,6 +591,10 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+NM_TRANSFORM_NAME
+GAS_TRANSFORM_NAME
+READELF_TRANSFORM_NAME
+STRIP_TRANSFORM_NAME
 EXTRA_RULES
 EGREP
 GREP
@@ -1272,6 +1276,11 @@ _ACEOF
 
   cat <<\_ACEOF
 
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
 System types:
   --build=BUILD     configure for building on BUILD [guessed]
   --host=HOST       cross-compile to build programs to run on HOST [BUILD]
@@ -3458,6 +3467,53 @@ if test "${build}" = "${host}" -a "${host}" = "${target}"; then
 fi
 
 
+# Transform the name of some programs and generate the lib/pdtrace
+# test tool.
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  STRIP_TRANSFORM_NAME=`echo strip | sed -e "$gdb_ac_transform"`
+  if test "xSTRIP_TRANSFORM_NAME" = x; then
+     STRIP_TRANSFORM_NAME=strip
+  fi
+
+
+
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  READELF_TRANSFORM_NAME=`echo readelf | sed -e "$gdb_ac_transform"`
+  if test "xREADELF_TRANSFORM_NAME" = x; then
+     READELF_TRANSFORM_NAME=readelf
+  fi
+
+
+
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  GAS_TRANSFORM_NAME=`echo as | sed -e "$gdb_ac_transform"`
+  if test "xGAS_TRANSFORM_NAME" = x; then
+     GAS_TRANSFORM_NAME=as
+  fi
+
+
+
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
+  NM_TRANSFORM_NAME=`echo nm | sed -e "$gdb_ac_transform"`
+  if test "xNM_TRANSFORM_NAME" = x; then
+     NM_TRANSFORM_NAME=nm
+  fi
+
+
+ac_config_files="$ac_config_files lib/pdtrace"
+
+
 ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile gdb.cell/Makefile gdb.compile/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.guile/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.perf/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
 
 cat >confcache <<\_ACEOF
@@ -4158,6 +4214,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 for ac_config_target in $ac_config_targets
 do
   case $ac_config_target in
+    "lib/pdtrace") CONFIG_FILES="$CONFIG_FILES lib/pdtrace" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "gdb.ada/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.ada/Makefile" ;;
     "gdb.arch/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.arch/Makefile" ;;
@@ -4599,6 +4656,11 @@ which seems to be undefined.  Please make sure it is defined." >&2;}
 
   esac
 
+
+  case $ac_file$ac_mode in
+    "lib/pdtrace":F) chmod +x lib/pdtrace ;;
+
+  esac
 done # for ac_tag
 
 
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 5037723..9de9fcc 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -96,6 +96,15 @@ if test "${build}" = "${host}" -a "${host}" = "${target}"; then
 fi
 AC_SUBST(EXTRA_RULES)
 
+# Transform the name of some programs and generate the lib/pdtrace
+# test tool.
+AC_ARG_PROGRAM
+GDB_AC_TRANSFORM(strip, STRIP_TRANSFORM_NAME)
+GDB_AC_TRANSFORM(readelf, READELF_TRANSFORM_NAME)
+GDB_AC_TRANSFORM(as, GAS_TRANSFORM_NAME)
+GDB_AC_TRANSFORM(nm, NM_TRANSFORM_NAME)
+AC_CONFIG_FILES([lib/pdtrace], [chmod +x lib/pdtrace])
+
 AC_OUTPUT([Makefile \
   gdb.ada/Makefile \
   gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile \
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.c b/gdb/testsuite/gdb.base/dtrace-probe.c
new file mode 100644
index 0000000..29933ad
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.c
@@ -0,0 +1,38 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014, 2015 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/>.  */
+
+#include "dtrace-probe.h"
+
+int
+main ()
+{
+  char *name = "application";
+
+  TEST_TWO_LOCATIONS ();
+  
+  int i = 0;
+  while (i < 10)
+    {
+      i++;
+      if (TEST_PROGRESS_COUNTER_ENABLED ())
+	TEST_PROGRESS_COUNTER (name, i);
+      else
+	TEST_TWO_LOCATIONS ();
+    }
+      
+  return 0; /* last break here */
+}
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.d b/gdb/testsuite/gdb.base/dtrace-probe.d
new file mode 100644
index 0000000..6bcbf34
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.d
@@ -0,0 +1,21 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014, 2015 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/>.  */
+
+provider test {
+  probe progress__counter (char *, int);
+  probe two__locations  ();
+};
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.exp b/gdb/testsuite/gdb.base/dtrace-probe.exp
new file mode 100644
index 0000000..e42e948
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.exp
@@ -0,0 +1,106 @@
+# Copyright (C) 2014, 2015 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 "dtrace.exp"
+
+# Run the tests.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc dtrace_test {} {
+    global testfile hex srcfile binfile
+
+    standard_testfile
+    
+    if {[dtrace_build_usdt_test_program] == -1} {
+        untested "could not compile test program"
+        return -1
+    }
+
+    clean_restart ${binfile}
+    
+    if ![runto_main] {
+        return -1
+    }
+
+    gdb_test "print \$_probe_argc" "No probe at PC $hex" \
+        "check argument not at probe point"
+
+    # Test the 'info probes' command.
+    gdb_test "info probes dtrace" \
+        "test *progress-counter *$hex +no.*test *two-locations *$hex +always.*test *two-locations *$hex +always.*" \
+        "info probes dtrace"
+
+    # Disabling the probe test:two-locations shall have no effect,
+    # since no is-enabled probes are defined for it in the object
+    # file.
+
+    gdb_test "disable probe test two-locations" \
+	"Probe test:two-locations cannot be disabled.*" \
+	"disable probe test two-locations"
+
+    # On the other hand, the probe test:progress-counter can be
+    # enabled and then disabled again.
+
+    gdb_test "enable probe test progress-counter" \
+	"Probe test:progress-counter enabled.*" \
+	"enable probe test progress-counter"
+
+    gdb_test "disable probe test progress-counter" \
+	"Probe test:progress-counter disabled.*" \
+	"disable probe test progress-counter"
+
+    # Since test:progress-counter is disabled we can run to the second
+    # instance of the test:two-locations probe.
+
+    if {![runto "-probe-dtrace test:two-locations"]} {
+	fail "run to the first test:two-locations probe point"
+    }
+    if {![runto "-probe-dtrace test:two-locations"]} {
+	fail "run to the second test:two-locations probe point"
+    }
+
+    # Go back to the breakpoint on main() and enable the
+    # test:progress-counter probe.  Set a breakpoint on it and see
+    # that it gets reached.
+
+    if ![runto_main] {
+	return -1
+    }
+
+    gdb_test "enable probe test progress-counter" \
+	"Probe test:progress-counter enabled.*" \
+	"enable probe test progress-counter"
+
+    gdb_test "break -probe-dtrace test:progress-counter" \
+	".*Breakpoint \[0-9\]+ .*" "set breakpoint in test:progress-counter"
+    gdb_continue_to_breakpoint "test:progress-counter"
+
+    # Test probe arguments.
+    gdb_test "print \$_probe_argc" " = 2" \
+        "print \$_probe_argc for probe progress-counter"
+    gdb_test "print \$_probe_arg0" \
+        " = $hex \"application\"" \
+        "print \$_probe_arg0 for probe progress-counter"
+    gdb_test "print \$_probe_arg1" " = 1" \
+        "print \$_probe_arg1 for probe progress-counter"
+
+    # Set a breakpoint with multiple probe locations.
+    gdb_test "break -pdtrace test:two-locations" \
+        "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
+        "set multi-location probe breakpoint (probe two-locations)"
+
+    return 0
+}
+
+dtrace_test
diff --git a/gdb/testsuite/lib/dtrace.exp b/gdb/testsuite/lib/dtrace.exp
new file mode 100644
index 0000000..e323b08
--- /dev/null
+++ b/gdb/testsuite/lib/dtrace.exp
@@ -0,0 +1,71 @@
+# Copyright 2014, 2015 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/>.
+
+# Generate a test program containing DTrace USDT probes, whose sources
+# are ${srcfile} and ${testfile}.d.  The sequence of commands used to
+# generate the test program is:
+#
+# 1. Generate a header file from ${testfile}.d using dtrace -h.
+# 2. Compile ${srcfile}.c.
+# 3. Generate an object file containing a DOF program using dtrace -G.
+# 4. Link everything together to get the test program.
+#
+# Note that if DTrace is not found in the host system then this
+# function uses the pdtrace implementation, which is located at
+# testsuite/lib/pdtrace.
+#
+# This function requires 'testfile', 'srcfile' and 'binfile' to be
+# properly set.
+#
+# This function returns -1 on failure, 0 otherwise
+proc dtrace_build_usdt_test_program {} {
+    global testfile hex objdir srcdir srcfile subdir binfile
+    
+    # Make sure that dtrace is installed, it is the real one (not the
+    # script installed by SystemTap, for example) and of the right
+    # version (>= 0.4.0).  If it is not then use pdtrace instead.
+    set dtrace "dtrace"
+    set result [remote_exec host "$dtrace -V"]
+    if {[lindex $result 0] != 0 || ![regexp {^dtrace: Sun D [0-9]\.[0-9]\.[0-9]} [lindex $result 1]]} {
+	set dtrace "${objdir}/lib/pdtrace"
+    }
+    set dscript_file "${srcdir}/${subdir}/${testfile}.d"
+
+    # 1. Generate a header file from testprogram.d using dtrace -h.
+    set out_header_file [standard_output_file "${testfile}.h"]
+    set result [remote_exec host "$dtrace -h -s $dscript_file -o $out_header_file"]
+    verbose -log [lindex $result 1]
+    if {[lindex $result 0] != 0} {
+        return -1
+    }
+
+    # 2. Compile testprogram.c.
+    set options [list debug additional_flags=-I[file dirname $out_header_file]]
+    if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}.o" object ${options}] != ""} {
+        return -1
+    }
+
+    # 3. Generate an object file containing a DOF program using dtrace -G.
+    set result [remote_exec host "$dtrace -G -s $dscript_file -o ${binfile}-p.o ${binfile}.o"]
+    verbose -log [lindex $result 1]
+    if {[lindex $result 0] != 0} {
+        return -1
+    }
+
+    # 4. Link everything together to get the test program.
+    if {[gdb_compile "${binfile}.o ${binfile}-p.o" ${binfile} executable {debug}] != ""} {
+        return -1
+    }
+}
diff --git a/gdb/testsuite/lib/pdtrace.in b/gdb/testsuite/lib/pdtrace.in
new file mode 100755
index 0000000..118b017
--- /dev/null
+++ b/gdb/testsuite/lib/pdtrace.in
@@ -0,0 +1,1033 @@
+#!/bin/sh
+
+# A Poor(but Free)'s Man dtrace
+#
+# Copyright (C) 2014, 2015 Free Software Foundation, Inc.
+#
+# Contributed by Oracle, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+# DISCLAIMER DISCLAIMER DISCLAIMER
+# This script is a test tool.  As such it is in no way intended to
+# replace the "real" dtrace command for any practical purpose, apart
+# from testing the DTrace USDT probes support in GDB.
+
+# that said...
+#
+# pdtrace is a limited dtrace program, implementing a subset of its
+# functionality:
+#
+# - The generation of an ELF file containing an embedded dtrace
+#   program.  Equivalent to dtrace -G.
+#
+# - The generation of a header file with definitions for static
+#   probes.  Equivalent to dtrace -h.
+#
+# This allows to generate DTrace static probes without having to use
+# the user-level DTrace components.  The generated objects are 100%
+# compatible with DTrace and can be traced by the dtrace kernel module
+# like if they were generated by dtrace.
+#
+# Some of the known limitations of this implementation are:
+# - The input d-script must describe one provider, and only one.
+# - The "probe " directives in the d-file must not include argument
+#   names, just the types.  Thus something like `char *' is valid, but
+#   `char *name' is not.
+# - The command line options must precede other arguments, since the
+#   script uses the (more) portable getopts.
+# - Each probe header in the d-script must be contained in
+#   a single line.
+# - strip -K removes the debugging information from the input object
+#   file.
+# - The supported target platforms are i[3456]86 and x86_64.
+#
+# Please keep this code as portable as possible.  Restrict yourself to
+# POSIX sh.
+
+# This script uses the following external programs, defined in
+# variables.  Some of them are substituted by autoconf.
+
+TR=tr
+NM=@NM_TRANSFORM_NAME@
+EGREP=egrep
+SED=sed
+CUT=cut
+READELF=@READELF_TRANSFORM_NAME@
+SORT=sort
+EXPR=expr
+WC=wc
+UNIQ=uniq
+HEAD=head
+SEQ=seq
+AS=@GAS_TRANSFORM_NAME@
+STRIP=@STRIP_TRANSFORM_NAME@
+TRUE=true
+
+# Sizes for several DOF structures, in bytes.
+#
+# See linux/dtrace/dof.h for the definition of the referred
+# structures.
+
+dof_hdrsize=64      # sizeof(dtrace_dof_hdr)
+dof_secsize=32      # sizeof(dtrace_dof_sect)
+dof_probesize=48    # sizeof(dtrace_dof_probe)
+dof_providersize=44 # sizeof(dtrace_dof_provider)
+
+# Types for the several DOF sections.
+#
+# See linux/dtrace/dof_defines.h for a complete list of section types
+# along with their values.
+
+dof_sect_type_strtab=8
+dof_sect_type_provider=15
+dof_sect_type_probes=16
+dof_sect_type_prargs=17
+dof_sect_type_proffs=18
+dof_sect_type_prenoffs=26
+
+### Functions
+
+# Write a message to the standard error output and exit with an error
+# status.
+#
+# Arguments:
+#   $1 error message.
+
+f_panic()
+{
+    echo "error: $1" 1>&2; exit 1
+}
+
+# Write a usage message to the standard output and exit with an error
+# status.
+
+f_usage()
+{
+    printf "Usage: pdtrace [-32|-64] [-GhV] [-o output] [-s script] [ args ... ]\n\n"
+
+    printf "\t-32 generate 32-bit ELF files\n"
+    printf "\t-64 generate 64-bit ELF files\n\n"
+
+    printf "\t-G  generate an ELF file containing embedded dtrace program\n"
+    printf "\t-h  generate a header file with definitions for static probes\n"
+    printf "\t-o  set output file\n"
+    printf "\t-s  handle probes according to the specified D script\n"
+    printf "\t-V  report the DTrace API version implemented by the tool\n"
+    exit 2
+}
+
+# Write a version message to the standard output and exit with a
+# successful status.
+
+f_version()
+{
+    echo "pdtrace: Sun D 1.6.3"
+    exit
+}
+
+# Add a new record to a list and return it.
+#
+# Arguments:
+# $1 is the list.
+# $2 is the new record
+
+f_add_record()
+{
+    rec=$1
+    test -n "$rec" && \
+        { rec=$(printf %s\\n "$rec"; echo x); rec=${rec%x}; }
+    printf %s "$rec$2"
+}
+
+# Collect the providers and probes information from the input object
+# file.
+#
+# This function sets the values of the following global variables.
+# The values are structured in records, each record in a line.  The
+# fields of each record are separated in some cases by white
+# characters and in other cases by colon (:) characters.
+#
+# The type codes in the line format descriptors are:
+# S: string, D: decimal number
+#
+# probes
+#   Regular probes and is-enabled probes.
+#   TYPE(S) PROVIDER(S) NAME(S) OFFSET(D) BASE(D) BASE_SYM(S)
+# base_probes
+#   Base probes, i.e. probes sharing provider, name and container.
+#   PROVIDER(S) NAME(S) BASE(D) BASE_SYM(S)
+# providers
+#   List of providers.
+#   PROVIDER(S)
+# All the offsets are expressed in bytes.
+#
+# Input globals:
+#  objfile
+# Output globals:
+#  probes, base_probes, providers
+
+probes=
+base_probes=
+providers=
+probes_args=
+
+f_collect_probes()
+{
+    # Probe points are function calls to undefined functions featuring
+    # distinct names for both normal probes and is-enabled probes.
+    PROBE_REGEX="(__dtrace_([a-zA-Z_]+)___([a-zA-Z_]+))"
+    EPROBE_REGEX="(__dtraceenabled_([a-zA-Z_]+)___([a-zA-Z_]+))"
+
+    while read type symbol provider name; do
+          test -z "$type" && f_panic "No probe points found in $objfile"
+
+          provider=$(printf %s $provider | $TR -s _)
+          name=$(printf %s $name | $TR -s _)
+
+          # Search the object file for relocations defined for the
+          # probe symbols.  Then calculate the base address of the
+          # probe (along with the symbol associated with that base
+          # address) and the offset of the probe point.
+          for offset in $($READELF -W -r $objfile | $EGREP $symbol | $CUT -d' ' -f1)
+          do
+              # Figure out the base address for the probe.  This is
+              # done finding the function name in the text section of
+              # the object file located above the probed point.  But
+              # note that the relocation is for the address operand of
+              # the call instruction, so we have to subtract 1 to find
+              # the real probed point.
+              offset=$((0x$offset - 1))
+
+              # The addresses of is-enabled probes must point to the
+              # first NOP instruction in their patched instructions
+              # sequences, so modify them (see f_patch_objfile for the
+              # instruction sequences).
+              if test "$type" = "e"; then
+                  if test "$objbits" -eq "32"; then
+                      offset=$((offset + 2))
+                  else # 64 bits
+                      offset=$((offset + 3))
+                  fi
+              fi
+              
+              # Determine the base address of the probe and its
+              # corresponding function name.
+              funcs=$($NM -td $objfile | $EGREP "^[0-9]+ T " \
+                      | $CUT -d' ' -f1,3 | $SORT -n -r | $TR ' ' :)
+              for fun in $funcs; do
+                  func_off=$(printf %s $fun | $CUT -d: -f1)
+                  func_sym=$(printf %s $fun | $CUT -d: -f2)
+                  # Note that `expr' is used to remove leading zeros
+                  # to avoid FUNC_OFF to be interpreted as an octal
+                  # number in arithmetic contexts.
+                  test "$func_off" -le "$offset" && \
+                      { base=$($EXPR $func_off + 0); break; }
+              done
+              test -n "$base" || \
+                f_panic "could not find base address for probe at $objfile($o)"
+
+              # Emit the record for the probe.
+              probes=$(f_add_record "$probes" \
+                                    "$type $provider $name $(($offset - $base)) $base $func_sym")
+          done
+      done <<EOF
+$($NM $objfile | $EGREP " U $PROBE_REGEX" \
+            | $SED -E -e "s/.*$PROBE_REGEX.*/p \1 \2 \3/";
+     $NM $objfile | $EGREP " U $EPROBE_REGEX" \
+         | $SED -E -e "s/.*$EPROBE_REGEX.*/e \1 \2 \3/")
+EOF
+
+    # Build the list of providers and of base probes from the probes.
+    while read type provider name offset base base_sym; do
+        providers=$(f_add_record "$providers" "$provider")
+        base_probes=$(f_add_record "$base_probes" "$provider $name $base $base_sym")
+    done <<EOF
+$probes
+EOF
+    providers=$(printf %s\\n "$providers" | $SORT | $UNIQ)
+    base_probes=$(printf %s\\n "$base_probes" | $SORT | $UNIQ)
+}
+
+# Collect the argument counts and type strings for all the probes
+# described in the `probes' global variable.  This is done by
+# inspecting the d-script file provided by the user.
+#
+# This function sets the values of the following global variables.
+# The values are structured in records, each record in a line.  The
+# fields of each record are separated in some cases by white
+# characters and in other cases by colon (:) characters.
+#
+# The type codes in the line format descriptors are:
+# S: string, D: decimal number
+#
+# probes_args
+#   Probes arguments.
+#   PROVIDER(S):NAME(S):NARGS(D):ARG1(S):ARG2(S):...:ARGn(S)
+#
+# Input globals:
+#  probes
+# Output globals:
+#  probes_args
+# Arguments:
+#   $1 is the d-script file from which to extract the arguments
+#      information.
+
+f_collect_probes_args()
+{
+    dscript=$1
+    while read type provider name offset base base_sym; do
+        # Process normal probes only.  Is-enabled probes are not
+        # described in the d-script file and they don't receive any
+        # argument.
+        test "$type" = "p" || continue
+        
+        # Names are mangled in d-script files to make it possible to
+        # have underscore characters as part of the provider name and
+        # probe name.
+        m_provider=$(printf %s $provider | $SED -e 's/_/__/g')
+        m_name=$(printf %s $name | $SED -e 's/_/__/g')
+        
+        # Ignore this probe if the d-script file does not describe its
+        # provider.
+        $EGREP -q "provider +$m_provider" $dscript || continue
+        
+        # Look for the line containing the description of the probe.
+        # If we can't find it then ignore this probe.
+        line=$($EGREP "^ *probe +$m_name *\(.*\);" $dscript)
+        test -n "$line" || continue
+        
+        # Ok, extract the argument types from the probe prototype.
+        # This is fragile as hell as it requires the prototype to be
+        # in a single line.
+        args=""; nargs=0; line=$(printf %s "$line" | $SED -e 's/.*(\(.*\)).*/\1/')
+        set -f; IFS=,
+        for arg in $line; do
+            args="$args:$arg"
+            nargs=$((nargs + 1))
+        done
+        set +f; unset IFS
+
+        # Emit the record for the probe arguments.
+        probes_args=$(f_add_record "$probes_args" "$provider:$name:$nargs$args")
+    done <<EOF
+$probes
+EOF
+}
+
+# Functions to manipulate the global BCOUNT.
+
+BCOUNT=0
+
+f_incr_bcount()
+{
+    BCOUNT=$((BCOUNT + $1))
+}
+
+f_align_bcount()
+{
+    test $((BCOUNT % $1)) -eq 0 || BCOUNT=$((BCOUNT + ($1 - (BCOUNT % $1))))
+}
+
+# Generate a line of assembly code and add it to the asmprogram global
+# variable.
+#
+# Arguments:
+#   $1 string to generate in a line.
+
+asmprogram=
+
+f_gen_asm()
+{
+    line=$(printf "\t$1")
+    asmprogram=$(f_add_record "$asmprogram" "$line")
+}
+
+# Helper function to generate the assembly code of a DOF section
+# header.
+#
+# This function is used by `f_gen_dof_program'.
+#
+# Arguments:
+#   $1 is the name of the described section.
+#   $2 is the type of the described section.
+#   $3 is the alignment of the described section.
+#   $4 is the number of entities stored in the described section.
+#   $5 is the offset in the DOF program of the described section.
+#   $6 is the size of the described section, in bytes.
+
+f_gen_dof_sect_header()
+{
+    f_gen_asm ""
+    f_gen_asm "/* dtrace_dof_sect for the $1 section.  */"
+    f_gen_asm ".balign 8"
+    f_gen_asm ".4byte $2\t/* uint32_t dofs_type  */"
+    f_gen_asm ".4byte $3\t/* uint32_t dofs_align  */"
+    # The DOF_SECF_LOAD flag is 1 => loadable section.
+    f_gen_asm ".4byte 1\t/* uint32_t dofs_flags  */"
+    f_gen_asm ".4byte $4\t/* uint32_t dofs_entsize  */"
+    f_gen_asm ".8byte $5\t/* uint64_t dofs_offset  */"
+    f_gen_asm ".8byte $6\t/* uint64_t dofs_size  */"
+}
+
+# Generate a DOF program and assembly it in the output file.
+#
+# The DOF program generated by this function has the following
+# structure:
+#
+# HEADER
+# STRTAB OFFTAB EOFFTAB [PROBES PROVIDER]...
+# STRTAB_SECT OFFTAB_SECT EOFFTAB_SECT ARGTAB_SECT [PROBES_SECT PROVIDER_SECT]...
+#
+# Input globals:
+#   probes, base_probes, providers, probes_args, BCOUNT
+
+f_gen_dof_program()
+{   
+    ###### Variables used to cache information needed later.
+    
+    # Number of section headers in the generated DOF program.
+    dof_secnum=0
+    # Offset of section headers in the generated DOF program, in bytes.
+    dof_secoff=0
+
+    # Sizes of the STRTAB, OFFTAB and EOFFTAB sections, in bytes.
+    strtab_size=0
+    offtab_size=0
+    eofftab_size=0
+    
+    # Offsets of the STRTAB, OFFTAB EOFFTAB and PROBES sections in the
+    # generated DOF program.  In bytes.
+    strtab_offset=0
+    offtab_offset=0
+    eofftab_offset=0
+    argtab_offset=0
+    probes_offset=0
+    
+    # Indexes of the section headers of the STRTAB, OFFTAB, EOFFTAB and
+    # PROBES sections in the sections array.
+    strtab_sect_index=0
+    offtab_sect_index=0
+    eofftab_sect_index=0
+    argtab_sect_index=0
+    probes_sect_index=0
+
+    # First offsets and eoffsets of the base-probes.
+    # Lines: PROVIDER(S) NAME(S) BASE(D) (DOF_OFFSET(D)|DOF_EOFFSET(D))
+    probes_dof_offsets=
+    probes_dof_eoffsets=
+    
+    # Offsets in the STRTAB section for the first type of base probes.
+    # Record per line: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
+    probes_dof_types=
+
+
+    # Offsets of the provider names in the provider's STRTAB section.
+    # Lines: PROVIDER(S) OFFSET(D)
+    providers_dof_names=
+
+    # Offsets of the base-probe names in the provider's STRTAB section.
+    # Lines: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
+    probes_dof_names=
+    
+    # Offsets of the provider sections in the DOF program.
+    # Lines: PROVIDER(S) OFFSET(D)
+    providers_offsets=
+
+    ###### Generation phase.
+    
+    # The header of the DOF program contains a `struct
+    # dtrace_dof_hdr'.  Record its size, but it is written at the end
+    # of the function.
+    f_incr_bcount $dof_hdrsize; f_align_bcount 8
+
+    # The STRTAB section immediately follows the header.  It contains
+    # the following set of packed null-terminated strings:
+    #
+    # [PROVIDER [BASE_PROBE_NAME [BASE_PROBE_ARG_TYPE...]]...]...
+    strtab_offset=$BCOUNT
+    strtab_sect_index=$dof_secnum
+    dof_secnum=$((dof_secnum + 1))
+    f_gen_asm ""
+    f_gen_asm "/* The STRTAB section.  */"
+    f_gen_asm ".balign 8"
+    # Add the provider names.
+    off=0
+    while read provider; do
+        strtab_size=$(($strtab_size + ${#prov} + 1))
+        # Note the funny mangling...
+        f_gen_asm ".asciz \"$(printf %s $provider | $TR _ -)\""
+        providers_dof_names=$(f_add_record "$providers_dof_names" \
+                                           "$provider $off")
+        off=$(($off + ${#provider} + 1))
+
+        # Add the base-probe names.
+        while read p_provider name base base_sym; do
+            test "$p_provider" = "$provider" || continue
+            # And yes, more funny mangling...
+            f_gen_asm ".asciz \"$(printf %s $name | $TR _ -)\""
+            probes_dof_names=$(f_add_record "$probes_dof_names" \
+                                            "$p_provider $name $base $off")
+            off=$(($off + ${#name} + 1))
+            while read args; do
+                a_provider=$(printf %s "$args" | $CUT -d: -f1)
+                a_name=$(printf %s "$args" | $CUT -d: -f2)
+                test "$a_provider" = "$p_provider" \
+                    && test "$a_name" = "$name" \
+                    || continue
+
+                probes_dof_types=$(f_add_record "$probes_dof_types" \
+                                                "$a_provider $name $base $off")
+                nargs=$(printf %s "$args" | $CUT -d: -f3)
+                for n in $($SEQ $nargs); do
+                    arg=$(printf %s "$args" | $CUT -d: -f$(($n + 3)))
+                    f_gen_asm ".asciz \"${arg}\""
+                    off=$(($off + ${#arg} + 1))
+                done                
+            done <<EOF
+$probes_args
+EOF
+        done <<EOF
+$base_probes
+EOF
+    done <<EOF
+$providers
+EOF
+    strtab_size=$off
+    f_incr_bcount $strtab_size; f_align_bcount 8
+
+    # The OFFTAB section contains a set of 32bit words, one per
+    # defined regular probe.
+    offtab_offset=$BCOUNT
+    offtab_sect_index=$dof_secnum
+    dof_secnum=$((dof_secnum + 1))
+    f_gen_asm ""
+    f_gen_asm "/* The OFFTAB section.  */"
+    f_gen_asm ".balign 8"
+    off=0
+    while read type provider name offset base base_sym; do
+        test "$type" = "p" || continue
+        f_gen_asm ".4byte $offset\t/* probe ${provider}:${name}  */"
+        probes_dof_offsets=$(f_add_record "$probes_dof_offsets" \
+                                          "$provider $name $base $off")
+        off=$(($off + 4))
+    done <<EOF
+$probes
+EOF
+    offtab_size=$off
+    f_incr_bcount $offtab_size; f_align_bcount 8
+
+    # The EOFFTAB section contains a set of 32bit words, one per
+    # defined is-enabled probe.
+    eofftab_offset=$BCOUNT
+    eofftab_sect_index=$dof_secnum
+    dof_secnum=$((dof_secnum + 1))
+    f_gen_asm ""
+    f_gen_asm "/* The EOFFTAB section.  */"
+    f_gen_asm ".balign 8"
+    off=0
+    while read type provider name offset base base_sym; do
+        test "$type" = "e" || continue
+        f_gen_asm ".4byte $offset\t/* is-enabled probe ${provider}:${name}  */"
+        probes_dof_eoffsets=$(f_add_record "$probes_dof_eoffsets" \
+                                           "$provider $name $base $off")
+        off=$(($off + 4))
+    done <<EOF
+$probes
+EOF
+    eofftab_size=$off
+    f_incr_bcount $eofftab_size; f_align_bcount 8
+
+    # The ARGTAB section is empty, but nonetheless has a section
+    # header, so record its section index here.
+    argtab_offset=0
+    argtab_sect_index=$dof_secnum
+    dof_secnum=$((dof_secnum + 1))
+
+    # Generate a pair of sections PROBES and PROVIDER for each
+    # provider.
+    while read prov; do
+        # The PROBES section contains an array of `struct
+        # dtrace_dof_probe'.
+        #
+        # A `dtrace_dof_probe' entry characterizes the collection of
+        # probes and is-enabled probes sharing the same provider, name and
+        # base address.
+        probes_sect_index=$dof_secnum
+        dof_secnum=$((dof_secnum + 1))
+        probes_offset=$BCOUNT        
+        num_base_probes=$(printf %s\\n "$base_probes" | $WC -l)
+        while read provider name base base_sym; do
+            name_offset=$(printf %s\\n "$probes_dof_names" \
+                          | $EGREP "^$provider $name " | $CUT -d' ' -f4)
+
+            num_offsets=$(printf %s\\n "$probes_dof_offsets" \
+                          | $EGREP "^$provider $name [0-9]+ " | $WC -l)
+            
+            first_offset=0
+            test "$num_offsets" -gt 0 && \
+              first_offset=$(printf %s\\n "$probes_dof_offsets" \
+                             | $EGREP "^$provider $name " | $CUT -d' ' -f4 | $HEAD -1)
+
+            num_eoffsets=$(printf %s\\n "$probes_dof_eoffsets" \
+                           | $EGREP "^$provider $name [0-9]+ " | $WC -l)
+            first_eoffset=0
+            test "$num_eoffsets" -gt 0 && \
+              first_eoffset=$(printf %s "$probes_dof_eoffsets" \
+                              | $EGREP "^$provider $name " | $CUT -d' ' -f4 | $HEAD -1)
+
+            num_args=$(printf %s "$probes_args" \
+                       | $EGREP "^$provider:$name:" | $CUT -d: -f3 | $HEAD -1)
+ 
+            first_type=$(printf %s "$probes_dof_types" \
+                         | $EGREP "^$provider $name $base " | $CUT -d' ' -f4 | $HEAD -1)
+
+            reloctype=R_X86_64_GLOB_DAT
+            test "$objbits" = "32" && reloctype=R_386_32
+            
+            f_gen_asm ""
+            f_gen_asm "/* dtrace_dof_probe for ${provider}:${name} at ${base_sym}  */"
+            f_gen_asm ".balign 8"
+            f_gen_asm ".reloc ., $reloctype, $base_sym + 0"
+            f_gen_asm ".8byte ${base}\t/* uint64_t dofpr_addr  */"
+            f_gen_asm ".4byte 0\t/* uint32_t dofpr_func  */"
+            f_gen_asm ".4byte $name_offset\t/* uint32_t dofpr_name   */"
+            f_gen_asm ".4byte $first_type\t/* uint32_t dofpr_nargv  */"
+            f_gen_asm ".4byte 0\t/* uint32_t dofpr_xargv  */"
+            f_gen_asm ".4byte 0\t/* uint32_t dofpr_argidx */"
+            f_gen_asm ".4byte $(($first_offset/4))\t/* uint32_t dofpr_offidx  */"
+            f_gen_asm ".byte  $num_args\t/* uint8_t dofpr_nargc  */"
+            f_gen_asm ".byte  0\t/* uint8_t dofpr_xargc  */"
+            f_gen_asm ".2byte $num_offsets\t/* uint16_t dofpr_noffs  */"
+            f_gen_asm ".4byte $(($first_eoffset/4))\t/* uint32_t dofpr_enoffidx  */"
+            f_gen_asm ".2byte $num_eoffsets\t/* uint16_t dofpr_nenoffs  */"
+            f_gen_asm ".2byte 0\t/* uint16_t dofpr_pad1  */"
+            f_gen_asm ".4byte 0\t/* uint16_t dofpr_pad2  */"
+
+            f_incr_bcount "$dof_probesize"
+        done <<EOF
+$base_probes
+EOF
+
+        # The PROVIDER section contains a `struct dtrace_dof_provider'
+        # instance describing the provider for the probes above.
+        dof_secnum=$((dof_secnum + 1))
+        providers_offsets=$(f_add_record "$providers_offsets" \
+                                         "$prov $BCOUNT")
+        # The dtrace_dof_provider.
+        provider_name_offset=$(printf %s "$providers_dof_names" \
+                                      | $EGREP "^$prov " | $CUT -d' ' -f2)
+
+        f_gen_asm ""
+        f_gen_asm "/* dtrace_dof_provider for $prov  */"
+        f_gen_asm ".balign 8"
+        # Links to several DOF sections.
+        f_gen_asm ".4byte $strtab_sect_index\t/* uint32_t dofpv_strtab  */"
+        f_gen_asm ".4byte $probes_sect_index\t/* uint32_t dofpv_probes  */"
+        f_gen_asm ".4byte $argtab_sect_index\t/* uint32_t dofpv_prargs  */"
+        f_gen_asm ".4byte $offtab_sect_index\t/* uint32_t dofpv_proffs  */"
+        # Offset of the provider name into the STRTAB section.
+        f_gen_asm ".4byte $provider_name_offset\t/* uint32_t dofpv_name  */"
+        # The rest of fields can be 0 for our modest purposes :)
+        f_gen_asm ".4byte 0\t/* uint32_t dofpv_provattr  */"
+        f_gen_asm ".4byte 0\t/* uint32_t dofpv_modattr  */"
+        f_gen_asm ".4byte 0\t/* uint32_t dofpv_funcattr  */"
+        f_gen_asm ".4byte 0\t/* uint32_t dofpv_nameattr  */"
+        f_gen_asm ".4byte 0\t/* uint32_t dofpv_argsattr  */"
+        # But not this one, of course...
+        f_gen_asm ".4byte $eofftab_sect_index\t/* uint32_t dofpv_prenoffs  */"
+
+        f_incr_bcount $dof_providersize
+    done<<EOF
+$providers
+EOF
+    f_align_bcount 8
+
+    # The section headers follow, one per section defined above.
+    dof_secoff=$BCOUNT
+
+    f_gen_dof_sect_header STRTAB \
+                          $dof_sect_type_strtab \
+                          1 1 $strtab_offset $strtab_size
+    f_incr_bcount $dof_secsize; f_align_bcount 8
+
+    f_gen_dof_sect_header OFFTAB \
+                          $dof_sect_type_proffs \
+                          4 4 $offtab_offset $offtab_size
+    f_incr_bcount $dof_secsize; f_align_bcount 8
+
+    f_gen_dof_sect_header EOFFTAB \
+                          $dof_sect_type_prenoffs \
+                          4 4 $eofftab_offset $eofftab_size
+    f_incr_bcount $dof_secsize; f_align_bcount 8
+
+    f_gen_dof_sect_header ARGTAB \
+                          $dof_sect_type_prargs \
+                          4 1 $argtab_offset 0
+    f_incr_bcount $dof_secsize; f_align_bcount 8
+    
+    while read provider; do
+        provider_offset=$(printf %s "$providers_offsets" \
+                          | $EGREP "^$provider " | $CUT -d' ' -f2)
+        num_base_probes=$(printf %s\\n "$base_probes" | $WC -l)
+
+        f_gen_dof_sect_header "$provider probes" \
+                              $dof_sect_type_probes \
+                              8 $dof_probesize $probes_offset \
+                              $((num_base_probes * dof_probesize))
+        f_incr_bcount $dof_secsize; f_align_bcount 8
+
+        f_gen_dof_sect_header "$provider provider" \
+                              $dof_sect_type_provider \
+                              8 1 $provider_offset $dof_providersize
+        f_incr_bcount $dof_secsize; f_align_bcount 8
+    done <<EOF
+$providers
+EOF
+
+    # Finally, cook the header.
+    asmbody="$asmprogram"
+    asmprogram=""
+    f_gen_asm "/* File generated by pdtrace.  */"
+    f_gen_asm ""
+
+    f_gen_asm ".section .SUNW_dof,\"a\",\"progbits\""
+    f_gen_asm ".globl __SUNW_dof"
+    f_gen_asm ".hidden __SUNW_dof"
+    f_gen_asm ".size __SUNW_dof, ${BCOUNT}"
+    f_gen_asm ".type __SUNW_dof, @object"
+    f_gen_asm "__SUNW_dof:"
+
+    f_gen_asm ""
+    f_gen_asm "/* dtrace_dof_hdr */"
+    f_gen_asm ".balign 8"
+    f_gen_asm ".byte  0x7f, 'D, 'O, 'F\t/* dofh_ident[0..3] */"
+    f_gen_asm ".byte  2\t\t/* model: 1=ILP32, 2=LP64 */"
+    f_gen_asm ".byte  1\t\t/* encoding: 1: little-endian, 2: big-endian */"
+    f_gen_asm ".byte  2\t\t/* DOF version: 1 or 2.  Latest is 2 */"
+    f_gen_asm ".byte  2\t\t/* DIF version: 1 or 2.  Latest is 2 */"
+    f_gen_asm ".byte  8\t\t/* number of DIF integer registers */"
+    f_gen_asm ".byte  8\t\t/* number of DIF tuple registers */"
+    f_gen_asm ".byte  0, 0\t\t/* dofh_ident[10..11] */"
+    f_gen_asm ".4byte 0\t\t/* dofh_ident[12..15] */"
+    f_gen_asm ".4byte 0\t/* uint32_t dofh_flags  */"  # See Limitations above.
+    f_gen_asm ".4byte ${dof_hdrsize}\t/* uint32_t dofh_hdrsize  */"
+    f_gen_asm ".4byte ${dof_secsize}\t/* uint32_t dofh_secsize */"
+    f_gen_asm ".4byte ${dof_secnum}\t/* uint32_t dofh_secnum  */"
+    f_gen_asm ".8byte ${dof_secoff}\t/* uint64_t dofh_secoff  */"
+    f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_loadsz  */"
+    f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_filesz  */"
+    f_gen_asm ".8byte 0\t/* uint64_t dofh_pad  */"
+    f_gen_asm ""
+
+    # Ok, now assembly the program in OFILE
+    echo "$asmprogram$asmbody" | $AS -$objbits -o $ofile
+
+    # Next step is to change the sh_type of the ".SUNW_dof" section
+    # headers to 0x6ffffff4 (SHT_SUNW_dof).
+    #
+    # Note that this code relies in the fact that readelf will list
+    # the sections ordered in the same order than the section headers
+    # in the section header table of the file.
+    elfinfo=$($READELF -a $ofile)
+
+    # Mind the endianness.
+    if printf %s "$elfinfo" | $EGREP -q "little endian"; then
+        sht_sunw_dof=$(printf %s%s%s%s \\364 \\377 \\377 \\157)
+    else
+        sht_sunw_dof=$(printf %s%s%s%s \\157 \\377 \\377 \\364)
+    fi
+
+    shdr_start=$(printf %s "$elfinfo" \
+                | $EGREP "^[ \t]*Start of section headers:" \
+                | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+    test -n "$shdr_start" \
+        || f_panic "could not extract the start of shdr from $ofile"
+
+    shdr_num_entries=$(printf %s "$elfinfo" \
+                       | $EGREP "^[ \t]*Size of section headers:" \
+                       | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+    test -n "$shdr_num_entries" \
+         || f_panic "could not extract the number of shdr entries from $ofile"
+
+    shdr_entry_size=$(printf %s "$elfinfo" \
+                      | $EGREP "^[ \t]*Size of section headers:" \
+                      | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+    test -n "$shdr_entry_size" \
+         || f_panic "could not fetch the size of section headers from $ofile"
+
+    while read line; do
+        data=$(printf %s "$line" \
+               | $SED -E -e 's/.*\[(.*)\][ \t]+([a-zA-Z_.]+).*/\1:\2/')
+        num=$(printf %s "$data" | $CUT -d: -f1)
+        name=$(printf %s "$data" | $CUT -d: -f2)
+        if test "$name" = ".SUNW_dof"; then
+            # Patch the new sh_type in the proper entry of the section
+            # header table.
+            printf "$sht_sunw_dof" \
+                   | dd of=$ofile conv=notrunc count=4 ibs=1 bs=1 \
+                        seek=$((shdr_start + (shdr_entry_size * num) + 4)) \
+                        2> /dev/null
+            break
+        fi
+    done <<EOF
+$(printf %s "$elfinfo" | $EGREP "^[ \t]*\[[0-9 ]+\].*[A-Z]+.*PROGBITS")
+EOF
+
+}
+
+# Patch the probed points in the given object file, replacing the
+# function calls with NOPs.
+#
+# The probed points in the input object files are function calls.
+# This function replaces these function calls by some other
+# instruction sequences.  Which replacement to use depends on several
+# factors, as documented below.
+#
+# Arguments:
+#  $1 is the object file to patch.
+
+f_patch_objfile()
+{
+    objfile=$1
+    
+    # Several x86_64 instruction opcodes, in octal.
+    x86_op_nop=$(printf \\220)
+    x86_op_ret=$(printf \\303)
+    x86_op_call=$(printf \\350)
+    x86_op_jmp32=$(printf \\351)
+    x86_op_rex_rax=$(printf \\110)
+    x86_op_xor_eax_0=$(printf \\063)
+    x86_op_xor_eax_1=$(printf \\300)
+    
+    # Figure out the file offset of the text section in the object
+    # file.
+    text_off=0x$(objdump -j .text -h $objfile \
+                 | grep \.text | $TR -s ' ' | $CUT -d' ' -f 7)
+
+    while read type provider name offset base base_sym; do
+        # Calculate the offset of the probed point in the object file.
+        # Note that the `offset' of is-enabled probes is tweaked in
+        # `f_collect_probes" to point ahead the patching point.
+        probe_off=$((text_off + base + offset))
+        if test "$type" = "e"; then
+            if test "$objbits" -eq "32"; then
+                probe_off=$((probe_off - 2))
+            else # 64 bits
+                probe_off=$((probe_off - 3))
+            fi
+        fi
+
+        # The probed point can be either a CALL instruction or a JMP
+        # instruction (a tail call).  This has an impact on the
+        # patching sequence.  Fetch the first byte at the probed point
+        # and do the right thing.
+        nopret="$x86_op_nop"
+        byte=$(dd if=$objfile count=1 ibs=1 bs=1 skip=$probe_off 2> /dev/null)
+        test "$byte" = "$x86_op_jmp32" && nopret="$x86_op_ret"
+
+        # Determine the patching sequence.  It depends on the type of
+        # probe at hand (regular or is-enabled) and also if
+        # manipulating a 32bit or 64bit binary.
+        patchseq=
+        case $type in
+            p) patchseq=$(printf %s%s%s%s%s \
+                                 "$nopret" \
+                                 "$x86_op_nop" \
+                                 "$x86_op_nop" \
+                                 "$x86_op_nop" \
+                                 "$x86_op_nop")
+               ;;
+            e) test "$objbits" -eq 64 && \
+                 patchseq=$(printf %s%s%s%s%s \
+                                   "$x86_op_rex_rax" \
+                                   "$x86_op_xor_eax_0" \
+                                   "$x86_op_xor_eax_1" \
+                                   "$nopret" \
+                                   "$x86_op_nop")
+               test "$objbits" -eq 32 && \
+                 patchseq=$(printf %s%s%s%s%s \
+                                   "$x86_op_xor_eax_0" \
+                                   "$x86_op_xor_eax_1" \
+                                   "$nopret" \
+                                   "$x86_op_nop" \
+                                   "$x86_op_nop")
+               ;;
+            *) f_panic "internal error: wrong probe type $type";;
+        esac
+
+        # Patch!
+        printf %s "$patchseq" \
+               | dd of=$objfile conv=notrunc count=5 ibs=1 bs=1 seek=$probe_off 2> /dev/null
+    done <<EOF
+$probes
+EOF
+    
+    # Finally, we have to remove the __dtrace_* and __dtraceenabled_*
+    # symbols from the object file, along with their respective
+    # relocations.
+    #
+    # Note that the most obvious call:
+    #   strip -v -N whatever -w foo.o
+    # will not work:
+    #   strip: not stripping symbol `whatever' because it is named in a relocation
+    #
+    # Fortunately using `-K !whatever' instead tricks strip to do the
+    # right thing, but this is black magic and may eventually stop
+    # working...
+    $STRIP -K '!__dtrace_*' -w $objfile
+    $STRIP -K '!__dtraceenabled_*' -w $objfile
+}
+
+# Read the input .d file and print a header file with macros to
+# invoke the probes defined in it.
+
+f_gen_header_file()
+{
+    guard=$(basename $ofile | $TR - _ | $CUT -d. -f1 | $TR a-z A-Z)
+    printf "/*\n * Generated by pdtrace.\n */\n\n"
+
+    printf "#ifndef _${guard}_H\n"
+    printf "#define _${guard}_H\n\n"
+
+    printf "#include <unistd.h>\n"
+    printf "#include <inttypes.h>\n"
+    printf \\n\\n
+
+    printf "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"
+
+    printf "#define _DTRACE_VERSION 1\n\n"
+
+    provider=$(cat $dfile | $EGREP "^ *provider +([a-zA-Z_]+)" \
+               | $SED -E -e 's/^ *provider +([a-zA-Z]+).*/\1/')
+    test -z "$provider" \
+        && f_panic "unable to parse the provider name from $dfile."
+    u_provider=$(printf %s "$provider" | $TR a-z A-Z | $TR -s _)
+    
+    cat $dfile | $EGREP "^ *probe +[a-zA-Z_]+ *\(.*\);" | \
+        while read line; do
+            # Extract the probe name.
+            name=$(printf %s "$line" \
+                   | $SED -E -e 's/^ *probe +([a-zA-Z_]+).*/\1/')
+            u_name=$(printf %s "$name" | $TR a-z A-Z | $TR -s _)
+
+            # Generate an arg1,arg2,...,argN line for the probe.
+            args=""; nargs=0; aline=$(printf %s "$line" | $SED -e 's/.*(\(.*\)).*/\1/')
+            set -f; IFS=,
+            for arg in $aline; do
+                args="${args}arg${nargs},"
+                nargs=$((nargs + 1))
+            done
+            set +f; unset IFS
+            args=${args%,}
+
+            echo "#if _DTRACE_VERSION"
+            echo ""
+            
+            # Emit the macros for the probe.
+            echo "#define ${u_provider}_${u_name}($args) \\"
+            echo "   __dtrace_${provider}___${name}($args)"
+            echo "#define ${u_provider}_${u_name}_ENABLED() \\"
+            echo "   __dtraceenabled_${provider}___${name}()"
+
+            # Emit the extern definitions for the probe dummy
+            # functions.
+            echo ""
+            printf %s\\n "$line" \
+                | $SED -E -e "s/^ *probe +/extern void __dtrace_${provider}___/"
+            echo "extern int __dtraceenabled_${provider}___${name}(void);"
+
+
+            printf "\n#else\n"
+
+            # Emit empty macros for the probe
+            echo "#define ${u_provider}_${u_name}($args)"
+            echo "#define ${u_provider}_${u_name}_ENABLED() (0)"
+
+            printf "\n#endif /* _DTRACE_VERSION */\n"
+        done
+
+    printf "#ifdef __cplusplus\n}\n#endif\n\n"
+    printf "#endif /* _${guard}_H */\n"
+}
+
+### Main program.
+
+# Process command line arguments.
+
+test "$#" -eq "0" && f_usage
+
+genelf=0
+genheader=0
+objbits=64
+ofile=
+dfile=
+while getopts VG3264hs:o: name; do
+    case $name in
+        V) f_version;;
+        s) dfile="$OPTARG";
+           test -f "$dfile" || f_panic "cannot read $dfile";;
+        o) ofile="$OPTARG";;
+        G) genelf=1;;
+        h) genheader=1;;
+        # Note the trick to support -32
+        3) objbits=666;;
+        2) test "$objbits" -eq 666 || f_usage; objbits=32;;
+        # Likewise for -64
+        6) objbits=777;;
+        4) test "$objbits" -eq 777 || f_usage; objbits=64;;
+        ?) f_usage;;
+    esac
+done
+shift $(($OPTIND - 1))
+
+test "$objbits" -eq "32" || test "$objbits" -eq "64" \
+    || f_usage
+
+test $((genelf + genheader)) -gt 1 && \
+    { echo "Please use either -G or -h."; f_usage; }
+
+test -n "$dfile" || { echo "Please specify a .d file with -s."; exit 2; }
+
+if test "$genelf" -gt 0; then
+    # In this mode there must be a remaining argument: the name of the
+    # object file to inspect for probed points.
+    test "$#" -ne "1" && f_usage
+    test -f "$1" || f_panic "cannot read $1"
+    objfile=$1
+
+    # Collect probe information from the input object file and the
+    # d-script.
+    f_collect_probes $objfile    
+    f_collect_probes_args $dfile
+
+    # Generate the assembly code and assemble the DOF program in
+    # OFILE.  Then patch OBJFILE to remove the dummy probe calls.
+    f_gen_dof_program
+    f_patch_objfile $objfile
+fi
+
+if test "$genheader" -gt 0; then
+    test -n "$ofile" || { echo "Please specify an output file with -o."; exit 2; }
+    
+    # In this mode no extra arguments shall be present.
+    test "$#" -ne "0" && f_usage
+
+    f_gen_header_file > $ofile
+fi
+
+# pdtrace ends here.
-- 
1.7.10.4

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

* [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
  2015-02-02 10:57 ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-17  1:14   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch adds several gdbarch functions (along with the corresponding
predicates): `dtrace_parse_probe_argument', `dtrace_probe_is_enabled',
`dtrace_enable_probe' and `dtrace_disable_probe'.  These functions will
be implemented by target-specific code, and called from the DTrace
probes implementation in order to calculate the value of probe
arguments, and manipulate is-enabled probes.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* gdbarch.sh (dtrace_parse_probe_argument): New.
	(dtrace_probe_is_enabled): Likewise.
	(dtrace_enable_probe): Likewise.
	(dtrace_disable_probe): Likewise.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
---
 gdb/ChangeLog  |    9 ++++
 gdb/gdbarch.c  |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbarch.h  |   36 ++++++++++++++++
 gdb/gdbarch.sh |   16 +++++++
 4 files changed, 189 insertions(+)

diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index b35da35..aa1a369 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -303,6 +303,10 @@ struct gdbarch
   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;
+  gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument;
+  gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled;
+  gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe;
+  gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe;
   int has_global_solist;
   int has_global_breakpoints;
   gdbarch_has_shared_address_space_ftype *has_shared_address_space;
@@ -632,6 +636,10 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* 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 dtrace_parse_probe_argument, has predicate.  */
+  /* Skip verify of dtrace_probe_is_enabled, has predicate.  */
+  /* Skip verify of dtrace_enable_probe, has predicate.  */
+  /* Skip verify of dtrace_disable_probe, 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 */
@@ -847,6 +855,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: double_format = %s\n",
                       pformat (gdbarch->double_format));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dtrace_disable_probe_p() = %d\n",
+                      gdbarch_dtrace_disable_probe_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dtrace_disable_probe = <%s>\n",
+                      host_address_to_string (gdbarch->dtrace_disable_probe));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dtrace_enable_probe_p() = %d\n",
+                      gdbarch_dtrace_enable_probe_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dtrace_enable_probe = <%s>\n",
+                      host_address_to_string (gdbarch->dtrace_enable_probe));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dtrace_parse_probe_argument_p() = %d\n",
+                      gdbarch_dtrace_parse_probe_argument_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dtrace_parse_probe_argument = <%s>\n",
+                      host_address_to_string (gdbarch->dtrace_parse_probe_argument));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dtrace_probe_is_enabled_p() = %d\n",
+                      gdbarch_dtrace_probe_is_enabled_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dtrace_probe_is_enabled = <%s>\n",
+                      host_address_to_string (gdbarch->dtrace_probe_is_enabled));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
                       gdbarch_dummy_id_p (gdbarch));
   fprintf_unfiltered (file,
@@ -4203,6 +4235,102 @@ set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
 }
 
 int
+gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->dtrace_parse_probe_argument != NULL;
+}
+
+void
+gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->dtrace_parse_probe_argument != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_parse_probe_argument called\n");
+  gdbarch->dtrace_parse_probe_argument (gdbarch, pstate, narg);
+}
+
+void
+set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
+                                         gdbarch_dtrace_parse_probe_argument_ftype dtrace_parse_probe_argument)
+{
+  gdbarch->dtrace_parse_probe_argument = dtrace_parse_probe_argument;
+}
+
+int
+gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->dtrace_probe_is_enabled != NULL;
+}
+
+int
+gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->dtrace_probe_is_enabled != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_probe_is_enabled called\n");
+  return gdbarch->dtrace_probe_is_enabled (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch,
+                                     gdbarch_dtrace_probe_is_enabled_ftype dtrace_probe_is_enabled)
+{
+  gdbarch->dtrace_probe_is_enabled = dtrace_probe_is_enabled;
+}
+
+int
+gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->dtrace_enable_probe != NULL;
+}
+
+void
+gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->dtrace_enable_probe != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_enable_probe called\n");
+  gdbarch->dtrace_enable_probe (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch,
+                                 gdbarch_dtrace_enable_probe_ftype dtrace_enable_probe)
+{
+  gdbarch->dtrace_enable_probe = dtrace_enable_probe;
+}
+
+int
+gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->dtrace_disable_probe != NULL;
+}
+
+void
+gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->dtrace_disable_probe != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_disable_probe called\n");
+  gdbarch->dtrace_disable_probe (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch,
+                                  gdbarch_dtrace_disable_probe_ftype dtrace_disable_probe)
+{
+  gdbarch->dtrace_disable_probe = dtrace_disable_probe;
+}
+
+int
 gdbarch_has_global_solist (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index b266530..de773a3 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -59,6 +59,7 @@ struct syscall;
 struct agent_expr;
 struct axs_value;
 struct stap_parse_info;
+struct parser_state;
 struct ravenscar_arch_ops;
 struct elf_internal_linux_prpsinfo;
 struct mem_range;
@@ -1241,6 +1242,41 @@ typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, s
 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);
 
+/* DTrace related functions.
+   The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
+   NARG must be >= 0. */
+
+extern int gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
+extern void gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
+extern void set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument);
+
+/* True if the given ADDR does not contain the instruction sequence
+   corresponding to a disabled DTrace is-enabled probe. */
+
+extern int gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_dtrace_probe_is_enabled_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern int gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled);
+
+/* Enable a DTrace is-enabled probe at ADDR. */
+
+extern int gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_enable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe);
+
+/* Disable a DTrace is-enabled probe at ADDR. */
+
+extern int gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_disable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe);
+
 /* 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 e12b8b0..fcca995 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -985,6 +985,21 @@ M:int:stap_is_single_operand:const char *s:s
 # parser), and should advance the buffer pointer (p->arg).
 M:int:stap_parse_special_token:struct stap_parse_info *p:p
 
+# DTrace related functions.
+
+# The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
+# NARG must be >= 0.
+M:void:dtrace_parse_probe_argument:struct parser_state *pstate, int narg:pstate, narg
+
+# True if the given ADDR does not contain the instruction sequence
+# corresponding to a disabled DTrace is-enabled probe.
+M:int:dtrace_probe_is_enabled:CORE_ADDR addr:addr
+
+# Enable a DTrace is-enabled probe at ADDR.
+M:void:dtrace_enable_probe:CORE_ADDR addr:addr
+
+# Disable a DTrace is-enabled probe at ADDR.
+M:void:dtrace_disable_probe:CORE_ADDR addr:addr
 
 # True if the list of shared libraries is one and only for all
 # processes, as opposed to a list of shared libraries per inferior.
@@ -1213,6 +1228,7 @@ struct syscall;
 struct agent_expr;
 struct axs_value;
 struct stap_parse_info;
+struct parser_state;
 struct ravenscar_arch_ops;
 struct elf_internal_linux_prpsinfo;
 struct mem_range;
-- 
1.7.10.4

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

* [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (2 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-17  1:13   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch moves the `compute_probe_arg' and `compile_probe_arg' functions
from stap-probe.c to probe.c.  The rationale is that it is reasonable to
assume that all backends will provide the `$_probe_argN' convenience
variables, and that the user must be placed on the PC of the probe when
requesting that information.  The value and type of the argument can still be
determined by the probe backend via the `pops->evaluate_probe_argument' and
`pops->compile_to_ax' handlers.

Note that a test in gdb.base/stap-probe.exp had to be adjusted because the "No
SystemTap probe at PC" messages are now "No probe at PC".

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* probe.c (compute_probe_arg): Moved from stap-probe.c
	(compile_probe_arg): Likewise.
	(probe_funcs): Likewise.
	* stap-probe.c (compute_probe_arg): Moved to probe.c.
	(compile_probe_arg): Likewise.
	(probe_funcs): Likewise.

gdb/testsuite/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* gdb.base/stap-probe.exp (stap_test): Remove "SystemTap" from
	expected message when trying to access $_probe_* convenience
	variables while not on a probe.
---
 gdb/ChangeLog                         |    9 +++
 gdb/probe.c                           |  111 +++++++++++++++++++++++++++++++++
 gdb/stap-probe.c                      |  109 --------------------------------
 gdb/testsuite/ChangeLog               |    6 ++
 gdb/testsuite/gdb.base/stap-probe.exp |    2 +-
 5 files changed, 127 insertions(+), 110 deletions(-)

diff --git a/gdb/probe.c b/gdb/probe.c
index be3e656..98113eb 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -30,6 +30,9 @@
 #include "gdb_regex.h"
 #include "frame.h"
 #include "arch-utils.h"
+#include "value.h"
+#include "ax.h"
+#include "ax-gdb.h"
 #include <ctype.h>
 
 typedef struct bound_probe bound_probe_s;
@@ -826,6 +829,87 @@ will show information about all types of probes."),
   return &info_probes_cmdlist;
 }
 
+\f
+
+/* This is called to compute the value of one of the $_probe_arg*
+   convenience variables.  */
+
+static struct value *
+compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
+		   void *data)
+{
+  struct frame_info *frame = get_selected_frame (_("No frame selected"));
+  CORE_ADDR pc = get_frame_pc (frame);
+  int sel = (int) (uintptr_t) data;
+  struct bound_probe pc_probe;
+  const struct sym_probe_fns *pc_probe_fns;
+  unsigned n_args;
+
+  /* SEL == -1 means "_probe_argc".  */
+  gdb_assert (sel >= -1);
+
+  pc_probe = find_probe_by_pc (pc);
+  if (pc_probe.probe == NULL)
+    error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+  n_args = get_probe_argument_count (pc_probe.probe, frame);
+  if (sel == -1)
+    return value_from_longest (builtin_type (arch)->builtin_int, n_args);
+
+  if (sel >= n_args)
+    error (_("Invalid probe argument %d -- probe has %u arguments available"),
+	   sel, n_args);
+
+  return evaluate_probe_argument (pc_probe.probe, sel, frame);
+}
+
+/* This is called to compile one of the $_probe_arg* convenience
+   variables into an agent expression.  */
+
+static void
+compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
+		   struct axs_value *value, void *data)
+{
+  CORE_ADDR pc = expr->scope;
+  int sel = (int) (uintptr_t) data;
+  struct bound_probe pc_probe;
+  const struct sym_probe_fns *pc_probe_fns;
+  int n_args;
+  struct frame_info *frame = get_selected_frame (NULL);
+
+  /* SEL == -1 means "_probe_argc".  */
+  gdb_assert (sel >= -1);
+
+  pc_probe = find_probe_by_pc (pc);
+  if (pc_probe.probe == NULL)
+    error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+  n_args = get_probe_argument_count (pc_probe.probe, frame);
+
+  if (sel == -1)
+    {
+      value->kind = axs_rvalue;
+      value->type = builtin_type (expr->gdbarch)->builtin_int;
+      ax_const_l (expr, n_args);
+      return;
+    }
+
+  gdb_assert (sel >= 0);
+  if (sel >= n_args)
+    error (_("Invalid probe argument %d -- probe has %d arguments available"),
+	   sel, n_args);
+
+  pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
+}
+
+static const struct internalvar_funcs probe_funcs =
+{
+  compute_probe_arg,
+  compile_probe_arg,
+  NULL
+};
+
+
 VEC (probe_ops_cp) *all_probe_ops;
 
 void _initialize_probe (void);
@@ -835,6 +919,33 @@ _initialize_probe (void)
 {
   VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
 
+  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
+				(void *) (uintptr_t) -1);
+  create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
+				(void *) (uintptr_t) 0);
+  create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
+				(void *) (uintptr_t) 1);
+  create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
+				(void *) (uintptr_t) 2);
+  create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
+				(void *) (uintptr_t) 3);
+  create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
+				(void *) (uintptr_t) 4);
+  create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
+				(void *) (uintptr_t) 5);
+  create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
+				(void *) (uintptr_t) 6);
+  create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
+				(void *) (uintptr_t) 7);
+  create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
+				(void *) (uintptr_t) 8);
+  create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
+				(void *) (uintptr_t) 9);
+  create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
+				(void *) (uintptr_t) 10);
+  create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
+				(void *) (uintptr_t) 11);
+
   add_cmd ("all", class_info, info_probes_command,
 	   _("\
 Show information about all type of probes."),
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index e534b6d..e898f7e 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1365,79 +1365,6 @@ stap_probe_destroy (struct probe *probe_generic)
 
 \f
 
-/* This is called to compute the value of one of the $_probe_arg*
-   convenience variables.  */
-
-static struct value *
-compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
-		   void *data)
-{
-  struct frame_info *frame = get_selected_frame (_("No frame selected"));
-  CORE_ADDR pc = get_frame_pc (frame);
-  int sel = (int) (uintptr_t) data;
-  struct bound_probe pc_probe;
-  const struct sym_probe_fns *pc_probe_fns;
-  unsigned n_args;
-
-  /* SEL == -1 means "_probe_argc".  */
-  gdb_assert (sel >= -1);
-
-  pc_probe = find_probe_by_pc (pc);
-  if (pc_probe.probe == NULL)
-    error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
-
-  n_args = get_probe_argument_count (pc_probe.probe, frame);
-  if (sel == -1)
-    return value_from_longest (builtin_type (arch)->builtin_int, n_args);
-
-  if (sel >= n_args)
-    error (_("Invalid probe argument %d -- probe has %u arguments available"),
-	   sel, n_args);
-
-  return evaluate_probe_argument (pc_probe.probe, sel, frame);
-}
-
-/* This is called to compile one of the $_probe_arg* convenience
-   variables into an agent expression.  */
-
-static void
-compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
-		   struct axs_value *value, void *data)
-{
-  CORE_ADDR pc = expr->scope;
-  int sel = (int) (uintptr_t) data;
-  struct bound_probe pc_probe;
-  const struct sym_probe_fns *pc_probe_fns;
-  int n_args;
-  struct frame_info *frame = get_selected_frame (NULL);
-
-  /* SEL == -1 means "_probe_argc".  */
-  gdb_assert (sel >= -1);
-
-  pc_probe = find_probe_by_pc (pc);
-  if (pc_probe.probe == NULL)
-    error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
-
-  n_args = get_probe_argument_count (pc_probe.probe, frame);
-
-  if (sel == -1)
-    {
-      value->kind = axs_rvalue;
-      value->type = builtin_type (expr->gdbarch)->builtin_int;
-      ax_const_l (expr, n_args);
-      return;
-    }
-
-  gdb_assert (sel >= 0);
-  if (sel >= n_args)
-    error (_("Invalid probe argument %d -- probe has %d arguments available"),
-	   sel, n_args);
-
-  pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
-}
-
-\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'
@@ -1514,15 +1441,6 @@ stap_clear_semaphore (struct probe *probe_generic, struct objfile *objfile,
   stap_modify_semaphore (addr, 0, gdbarch);
 }
 
-/* Implementation of `$_probe_arg*' set of variables.  */
-
-static const struct internalvar_funcs probe_funcs =
-{
-  compute_probe_arg,
-  compile_probe_arg,
-  NULL
-};
-
 /* Helper function that parses the information contained in a
    SystemTap's probe.  Basically, the information consists in:
 
@@ -1793,33 +1711,6 @@ _initialize_stap_probe (void)
 			     show_stapexpressiondebug,
 			     &setdebuglist, &showdebuglist);
 
-  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
-				(void *) (uintptr_t) -1);
-  create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
-				(void *) (uintptr_t) 0);
-  create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
-				(void *) (uintptr_t) 1);
-  create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
-				(void *) (uintptr_t) 2);
-  create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
-				(void *) (uintptr_t) 3);
-  create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
-				(void *) (uintptr_t) 4);
-  create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
-				(void *) (uintptr_t) 5);
-  create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
-				(void *) (uintptr_t) 6);
-  create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
-				(void *) (uintptr_t) 7);
-  create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
-				(void *) (uintptr_t) 8);
-  create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
-				(void *) (uintptr_t) 9);
-  create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
-				(void *) (uintptr_t) 10);
-  create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
-				(void *) (uintptr_t) 11);
-
   add_cmd ("stap", class_info, info_probes_stap_command,
 	   _("\
 Show information about SystemTap static probes.\n\
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
index 73e6ca3..7310b25 100644
--- a/gdb/testsuite/gdb.base/stap-probe.exp
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -30,7 +30,7 @@ proc stap_test {exec_name {arg ""}} {
 	return -1
     }
 
-    gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+    gdb_test "print \$_probe_argc" "No probe at PC $hex" \
 	"check argument not at probe point"
 
     gdb_test "info probes stap" \
-- 
1.7.10.4

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

* [PATCH V4 3/9] New commands `enable probe' and `disable probe'.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (5 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-02 16:01   ` Eli Zaretskii
  2015-02-17  1:54   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch adds the above-mentioned commands to the generic probe
abstraction implemented in probe.[ch].  The effects associated to
enabling or disabling a probe depend on the type of probe being
handled, and is triggered by invoking two back-end hooks in
`probe_ops'.

In case some particular probe type does not support the notion of
enabling and/or disabling, the corresponding fields on `probe_ops' can
be initialized to NULL.  This is the case of SystemTap probes.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* stap-probe.c (stap_probe_ops): Add NULLs in the static
	stap_probe_ops for `enable_probe' and `disable_probe'.
	* probe.c (enable_probes_command): New function.
	(disable_probes_command): Likewise.
	(_initialize_probe): Define the cli commands `enable probe' and
	`disable probe'.
	(parse_probe_linespec): New function.
	(info_probes_for_ops): Use parse_probe_linespec.
	* probe.h (probe_ops): New hooks `enable_probe' and
	`disable_probe'.

gdb/doc/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* gdb.texinfo (Static Probe Points): Cover the `enable probe' and
	`disable probe' commands.
---
 gdb/ChangeLog       |   13 +++++
 gdb/doc/ChangeLog   |    5 ++
 gdb/doc/gdb.texinfo |   29 ++++++++++
 gdb/probe.c         |  153 +++++++++++++++++++++++++++++++++++++++++++++------
 gdb/probe.h         |   12 ++++
 gdb/stap-probe.c    |    2 +
 6 files changed, 198 insertions(+), 16 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index aee17d3..4ab0bba 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5011,6 +5011,35 @@ given, all object files are considered.
 List the available static probes, from all types.
 @end table
 
+@cindex enabling and disabling probes
+Some probe points can be enabled and/or disabled.  The effect of
+enabling or disabling a probe depends on the type of probe being
+handled.  @code{SystemTap} probes cannot be disabled.
+
+You can enable (or disable) one or more probes using the following
+commands, with optional arguments:
+
+@table @code
+@kindex enable probes
+@item enable probes @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 enable.  If omitted,
+all probes from all providers are enabled.
+
+If given, @var{name} is a regular expression to match against probe
+names when selecting which probes to enable.  If omitted, probe names
+are not considered when deciding whether to enable 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.
+
+@kindex disable probes
+@item disable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+See the @code{enable probes} command above for a description of the
+optional arguments accepted by this command.
+@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
diff --git a/gdb/probe.c b/gdb/probe.c
index 98113eb..741c120 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -527,6 +527,24 @@ exists_probe_with_pops (VEC (bound_probe_s) *probes,
   return 0;
 }
 
+/* Helper function that parses a probe linespec of the form [PROVIDER
+   [PROBE [OBJNAME]]] from the provided string STR.  */
+
+static void
+parse_probe_linespec (const char *str, char **provider,
+		      char **probe_name, char **objname)
+{
+  *probe_name = *objname = NULL;
+
+  *provider = extract_arg_const (&str);
+  if (*provider != NULL)
+    {
+      *probe_name = extract_arg_const (&str);
+      if (*probe_name != NULL)
+	*objname = extract_arg_const (&str);
+    }
+}
+
 /* See comment in probe.h.  */
 
 void
@@ -546,22 +564,10 @@ info_probes_for_ops (const char *arg, int from_tty,
   struct bound_probe *probe;
   struct gdbarch *gdbarch = get_current_arch ();
 
-  /* Do we have a `provider:probe:objfile' style of linespec?  */
-  provider = extract_arg_const (&arg);
-  if (provider)
-    {
-      make_cleanup (xfree, provider);
-
-      probe_name = extract_arg_const (&arg);
-      if (probe_name)
-	{
-	  make_cleanup (xfree, probe_name);
-
-	  objname = extract_arg_const (&arg);
-	  if (objname)
-	    make_cleanup (xfree, objname);
-	}
-    }
+  parse_probe_linespec (arg, &provider, &probe_name, &objname);
+  make_cleanup (xfree, provider);
+  make_cleanup (xfree, probe_name);
+  make_cleanup (xfree, objname);
 
   probes = collect_probes (objname, provider, probe_name, pops);
   make_cleanup (VEC_cleanup (probe_p), &probes);
@@ -689,6 +695,98 @@ info_probes_command (char *arg, int from_tty)
   info_probes_for_ops (arg, from_tty, NULL);
 }
 
+/* Implementation of the `enable probes' command.  */
+
+static void
+enable_probes_command (char *arg, int from_tty)
+{
+  char *provider, *probe_name = NULL, *objname = NULL;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  VEC (bound_probe_s) *probes;
+  struct bound_probe *probe;
+  int i;
+
+  parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+  make_cleanup (xfree, provider);
+  make_cleanup (xfree, probe_name);
+  make_cleanup (xfree, objname);
+
+  probes = collect_probes (objname, provider, probe_name, NULL);
+  if (VEC_empty (bound_probe_s, probes))
+    {
+      ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+      do_cleanups (cleanup);
+      return;
+    }
+
+  /* Enable the selected probes, provided their backends support the
+     notion of enabling a probe.  */
+  for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
+    {
+      const struct probe_ops *pops = probe->probe->pops;
+
+      if (pops->enable_probe != NULL)
+	{
+	  pops->enable_probe (probe->probe);
+	  ui_out_message (current_uiout, 0,
+			  _("Probe %s:%s enabled.\n"),
+			  probe->probe->provider, probe->probe->name);
+	}
+      else
+	ui_out_message (current_uiout, 0,
+			_("Probe %s:%s cannot be enabled.\n"),
+			probe->probe->provider, probe->probe->name);
+    }
+
+  do_cleanups (cleanup);
+}
+
+/* Implementation of the `disable probes' command.  */
+
+static void
+disable_probes_command (char *arg, int from_tty)
+{
+  char *provider, *probe_name = NULL, *objname = NULL;
+  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+  VEC (bound_probe_s) *probes;
+  struct bound_probe *probe;
+  int i;
+
+  parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+  make_cleanup (xfree, provider);
+  make_cleanup (xfree, probe_name);
+  make_cleanup (xfree, objname);
+
+  probes = collect_probes (objname, provider, probe_name, NULL /* pops */);
+  if (VEC_empty (bound_probe_s, probes))
+    {
+      ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+      do_cleanups (cleanup);
+      return;
+    }
+
+  /* Disable the selected probes, provided their backends support the
+     notion of enabling a probe.  */
+  for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
+    {
+      const struct probe_ops *pops = probe->probe->pops;
+
+      if (pops->disable_probe != NULL)
+	{
+	  pops->disable_probe (probe->probe);
+	  ui_out_message (current_uiout, 0,
+			  _("Probe %s:%s disabled.\n"),
+			  probe->probe->provider, probe->probe->name);
+	}
+      else
+	ui_out_message (current_uiout, 0,
+			_("Probe %s:%s cannot be disabled.\n"),
+			probe->probe->provider, probe->probe->name);
+    }
+
+  do_cleanups (cleanup);
+}
+
 /* See comments in probe.h.  */
 
 CORE_ADDR
@@ -950,4 +1048,27 @@ _initialize_probe (void)
 	   _("\
 Show information about all type of probes."),
 	   info_probes_cmdlist_get ());
+
+  add_cmd ("probes", class_breakpoint, enable_probes_command, _("\
+Enable probes.\n\
+Usage: enable probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name.\n\
+If you do not specify any argument then the command will enable\n\
+all defined probes."),
+	   &enablelist);
+
+  add_cmd ("probes", class_breakpoint, disable_probes_command, _("\
+Disable probes.\n\
+Usage: disable probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name.\n\
+If you do not specify any argument then the command will disable\n\
+all defined probes."),
+	   &disablelist);
+
 }
diff --git a/gdb/probe.h b/gdb/probe.h
index 5df1976..e8d5dfe 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -138,6 +138,18 @@ struct probe_ops
 
     void (*gen_info_probes_table_values) (struct probe *probe,
 					  VEC (const_char_ptr) **values);
+
+    /* Enable a probe.  The semantics of "enabling" a probe depend on
+       the specific backend and the field can be NULL in case enabling
+       probes is not supported.  */
+
+    void (*enable_probe) (struct probe *probe);
+
+    /* Disable a probe.  The semantics of "disabling" a probe depend
+       on the specific backend and the field can be NULL in case
+       disabling probes is not supported.  */
+
+    void (*disable_probe) (struct probe *probe);
   };
 
 /* Definition of a vector of probe_ops.  */
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index e898f7e..eaf07b9 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1684,6 +1684,8 @@ static const struct probe_ops stap_probe_ops =
   stap_type_name,
   stap_gen_info_probes_table_header,
   stap_gen_info_probes_table_values,
+  NULL,  /* enable_probe  */
+  NULL   /* disable_probe  */
 };
 
 /* Implementation of the `info probes stap' command.  */
-- 
1.7.10.4

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

* [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (6 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-17  1:37   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch adds the target-specific code in order to support the
calculation of DTrace probes arguments in x86_64 targets, and also the
enabling and disabling of probes.  This is done by implementing the
`dtrace_*' gdbarch handlers.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* amd64-linux-tdep.c: Include "parser-defs.h" and "user-regs.h".
	(amd64_dtrace_parse_probe_argument): New function.
	(amd64_dtrace_probe_is_enabled): Likewise.
	(amd64_dtrace_enable_probe): Likewise.
	(amd64_dtrace_disable_probe): Likewise.
	(amd64_linux_init_abi): Register the
	`gdbarch_dtrace_probe_argument', `gdbarch_dtrace_enable_probe',
	`gdbarch_dtrace_disable_probe' and
	`gdbarch_dtrace_probe_is_enabled' hooks.
	(amd64_dtrace_disabled_probe_sequence_1): New constant.
	(amd64_dtrace_disabled_probe_sequence_2): Likewise.
	(amd64_dtrace_enable_probe_sequence): Likewise.
	(amd64_dtrace_disable_probe_sequence): Likewise.
---
 gdb/ChangeLog          |   16 ++++++
 gdb/amd64-linux-tdep.c |  148 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 164 insertions(+)

diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 42d884e..ffa85f4 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -28,6 +28,8 @@
 #include "gdbtypes.h"
 #include "reggroups.h"
 #include "regset.h"
+#include "parser-defs.h"
+#include "user-regs.h"
 #include "amd64-linux-tdep.h"
 #include "i386-linux-tdep.h"
 #include "linux-tdep.h"
@@ -1643,6 +1645,146 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
       &amd64_linux_xstateregset, "XSAVE extended state", cb_data);
 }
 
+/* The instruction sequences used in x86_64 machines for a
+   disabled is-enabled probe.  */
+
+const gdb_byte amd64_dtrace_disabled_probe_sequence_1[] = {
+  /* xor %rax, %rax */  0x48, 0x33, 0xc0,
+  /* nop            */  0x90,
+  /* nop            */  0x90
+};
+
+const gdb_byte amd64_dtrace_disabled_probe_sequence_2[] = {
+  /* xor %rax, %rax */  0x48, 0x33, 0xc0,
+  /* ret            */  0xc3,
+  /* nop            */  0x90
+};
+
+/* The instruction sequence used in x86_64 machines for enabling a
+   DTrace is-enabled probe.  */
+
+const gdb_byte amd64_dtrace_enable_probe_sequence[] = {
+  /* mov $0x1, %eax */ 0xb8, 0x01, 0x00, 0x00, 0x00
+};
+
+/* The instruction sequence used in x86_64 machines for disabling a
+   DTrace is-enabled probe.  */
+
+const gdb_byte amd64_dtrace_disable_probe_sequence[] = {
+  /* xor %rax, %rax; nop; nop */ 0x48, 0x33, 0xC0, 0x90, 0x90
+};
+
+/* Implementation of `gdbarch_dtrace_probe_is_enabled', as defined in
+   gdbarch.h.  */
+
+static int
+amd64_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_byte buf[5];
+
+  /* This function returns 1 if the instructions at ADDR do _not_
+     follow any of the amd64_dtrace_disabled_probe_sequence_*
+     patterns.
+
+     Note that ADDR is offset 3 bytes from the beginning of these
+     sequences.  */
+  
+  read_code (addr - 3, buf, 5);
+  return (memcmp (buf, amd64_dtrace_disabled_probe_sequence_1, 5) != 0
+	  && memcmp (buf, amd64_dtrace_disabled_probe_sequence_2, 5) != 0);
+}
+
+/* Implementation of `gdbarch_dtrace_enable_probe', as defined in
+   gdbarch.h.  */
+
+static void
+amd64_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  /* Note also that ADDR is offset 3 bytes from the beginning of
+     amd64_dtrace_enable_probe_sequence.  */
+
+  write_memory (addr - 3, amd64_dtrace_enable_probe_sequence, 5);
+}
+
+/* Implementation of `gdbarch_dtrace_disable_probe', as defined in
+   gdbarch.h.  */
+
+static void
+amd64_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  /* Note also that ADDR is offset 3 bytes from the beginning of
+     amd64_dtrace_disable_probe_sequence.  */
+
+  write_memory (addr - 3, amd64_dtrace_disable_probe_sequence, 5);
+}
+
+/* Implementation of `gdbarch_dtrace_parse_probe_argument', as defined
+   in gdbarch.h.  */
+
+static void
+amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
+				   struct parser_state *pstate,
+				   int narg)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct frame_info *this_frame = get_selected_frame (NULL);
+  struct stoken str;
+
+  /* DTrace probe arguments can be found on the ABI-defined places for
+     regular arguments at the current PC.  The probe abstraction
+     currently supports up to 12 arguments for probes.  */
+
+  if (narg < 6)
+    {
+      static const int arg_reg_map[6] =
+	{
+	  AMD64_RDI_REGNUM,  /* Arg 1.  */
+	  AMD64_RSI_REGNUM,  /* Arg 2.  */
+	  AMD64_RDX_REGNUM,  /* Arg 3.  */
+	  AMD64_RCX_REGNUM,  /* Arg 4.  */
+	  AMD64_R8_REGNUM,   /* Arg 5.  */
+	  AMD64_R9_REGNUM    /* Arg 6.  */
+	};
+      int regno = arg_reg_map[narg];
+      const char *regname = user_reg_map_regnum_to_name (gdbarch, regno);
+
+      write_exp_elt_opcode (pstate, OP_REGISTER);
+      str.ptr = regname;
+      str.length = strlen (regname);
+      write_exp_string (pstate, str);
+      write_exp_elt_opcode (pstate, OP_REGISTER);
+    }
+  else
+    {
+      /* Additional arguments are passed on the stack.  */
+      CORE_ADDR sp;
+      const char *regname = user_reg_map_regnum_to_name (gdbarch, AMD64_RSP_REGNUM);
+
+      /* Displacement.  */
+      write_exp_elt_opcode (pstate, OP_LONG);
+      write_exp_elt_type (pstate, builtin_type (gdbarch)->builtin_long);
+      write_exp_elt_longcst (pstate, narg - 6);
+      write_exp_elt_opcode (pstate, OP_LONG);
+
+      /* Register: SP.  */
+      write_exp_elt_opcode (pstate, OP_REGISTER);
+      str.ptr = regname;
+      str.length = strlen (regname);
+      write_exp_string (pstate, str);
+      write_exp_elt_opcode (pstate, OP_REGISTER);
+
+      write_exp_elt_opcode (pstate, BINOP_ADD);
+
+      /* Cast to long. */
+      write_exp_elt_opcode (pstate, UNOP_CAST);
+      write_exp_elt_type (pstate,
+			  lookup_pointer_type (builtin_type (gdbarch)->builtin_long));
+      write_exp_elt_opcode (pstate, UNOP_CAST);
+
+      write_exp_elt_opcode (pstate, UNOP_IND);
+    }
+}
+
 static void
 amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1907,6 +2049,12 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
     (gdbarch, svr4_lp64_fetch_link_map_offsets);
+
+  /* Register DTrace handlers.  */
+  set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
+  set_gdbarch_dtrace_probe_is_enabled (gdbarch, amd64_dtrace_probe_is_enabled);
+  set_gdbarch_dtrace_enable_probe (gdbarch, amd64_dtrace_enable_probe);
+  set_gdbarch_dtrace_disable_probe (gdbarch, amd64_dtrace_disable_probe);
 }
 
 static void
-- 
1.7.10.4

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

* [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-17  1:35   ` Sergio Durigan Junior
  2015-02-02 10:57 ` [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch adds a new type of probe to GDB: the DTrace USDT probes.  The new
type is added by providing functions implementing all the entries of the
`probe_ops' structure defined in `probe.h'.  The implementation is
self-contained and does not depend on DTrace source code in any way.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* breakpoint.c (BREAK_ARGS_HELP): help string updated to mention
	the -probe-dtrace new vpossible value for PROBE_MODIFIER.
	* configure.ac (CONFIG_OBS): dtrace-probe.o added if BFD can
	handle ELF files.
	* Makefile.in (SFILES): dtrace-probe.c added.
	* configure: Regenerate.
	* dtrace-probe.c: New file.
	(SHT_SUNW_dof): New constant.
	(dtrace_probe_type): New enum.
	(dtrace_probe_arg): New struct.
	(dtrace_probe_arg_s): New typedef.
	(struct dtrace_probe_enabler): New struct.
	(dtrace_probe_enabler_s): New typedef.
	(dtrace_probe): New struct.
	(dtrace_probe_is_linespec): New function.
	(dtrace_dof_sect_type): New enum.
	(dtrace_dof_dofh_ident): Likewise.
	(dtrace_dof_encoding): Likewise.
	(DTRACE_DOF_ENCODE_LSB): Likewise.
	(DTRACE_DOF_ENCODE_MSB): Likewise.
	(dtrace_dof_hdr): New struct.
	(dtrace_dof_sect): Likewise.
	(dtrace_dof_provider): Likewise.
	(dtrace_dof_probe): Likewise.
	(DOF_UINT): New macro.
	(DTRACE_DOF_PTR): Likewise.
	(DTRACE_DOF_SECT): Likewise.
	(dtrace_process_dof_probe): New function.
	(dtrace_process_dof): Likewise.
	(dtrace_build_arg_exprs): Likewise.
	(dtrace_get_arg): Likewise.
	(dtrace_get_probes): Likewise.
	(dtrace_get_probe_argument_count): Likewise.
	(dtrace_can_evaluate_probe_arguments): Likewise.
	(dtrace_evaluate_probe_argument): Likewise.
	(dtrace_compile_to_ax): Likewise.
	(dtrace_probe_destroy): Likewise.
	(dtrace_gen_info_probes_table_header): Likewise.
	(dtrace_gen_info_probes_table_values): Likewise.
	(dtrace_probe_is_enabled): Likewise.
	(dtrace_probe_ops): New variable.
	(info_probes_dtrace_command): New function.
	(_initialize_dtrace_probe): Likewise.
	(dtrace_type_name): Likewise.
---
 gdb/ChangeLog      |   47 +++
 gdb/Makefile.in    |    3 +-
 gdb/breakpoint.c   |    3 +-
 gdb/configure      |    2 +-
 gdb/configure.ac   |    2 +-
 gdb/dtrace-probe.c |  909 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 962 insertions(+), 4 deletions(-)
 create mode 100644 gdb/dtrace-probe.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8addef4..e933b45 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -820,7 +820,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
 	d-exp.y d-lang.c d-valprint.c \
 	cp-name-parser.y \
-	dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
+	dbxread.c demangle.c dictionary.c disasm.c doublest.c \
+	dtrace-probe.c dummy-frame.c \
 	dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
 	dwarf2-frame-tailcall.c \
 	elfread.c environ.c eval.c event-loop.c event-top.c \
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index af0c2cf..48e551c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -15975,7 +15975,8 @@ all_tracepoints (void)
 command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
 PROBE_MODIFIER shall be present if the command is to be placed in a\n\
 probe point.  Accepted values are `-probe' (for a generic, automatically\n\
-guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\
+guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
+`-probe-dtrace' (for a DTrace probe).\n\
 LOCATION may be a line number, function name, or \"*\" and an address.\n\
 If a line number is specified, break at start of code for that line.\n\
 If a function is specified, break at start of code for that function.\n\
diff --git a/gdb/configure b/gdb/configure
index 9632f9a..30a54d2 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -13068,7 +13068,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
   LDFLAGS=$OLD_LDFLAGS
   LIBS=$OLD_LIBS
 if test $gdb_cv_var_elf = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
 
 $as_echo "#define HAVE_ELF 1" >>confdefs.h
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index dfc6947..39fcef2 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2074,7 +2074,7 @@ AC_SUBST(WIN32LIBS)
 GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
                  [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
 if test $gdb_cv_var_elf = yes; then
-  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
+  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
   AC_DEFINE(HAVE_ELF, 1,
 	    [Define if ELF support should be included.])
   # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
new file mode 100644
index 0000000..9b4a569
--- /dev/null
+++ b/gdb/dtrace-probe.c
@@ -0,0 +1,909 @@
+/* DTrace probe support for GDB.
+
+   Copyright (C) 2014, 2015 Free Software Foundation, Inc.
+
+   Contributed by Oracle, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "probe.h"
+#include "vec.h"
+#include "elf-bfd.h"
+#include "gdbtypes.h"
+#include "obstack.h"
+#include "objfiles.h"
+#include "complaints.h"
+#include "value.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "language.h"
+#include "parser-defs.h"
+#include "inferior.h"
+
+/* The type of the ELF sections where we will find the DOF programs
+   with information about probes.  */
+
+#ifndef SHT_SUNW_dof
+# define SHT_SUNW_dof	0x6ffffff4
+#endif
+
+/* Forward declaration.  */
+
+static const struct probe_ops dtrace_probe_ops;
+
+/* The following structure represents a single argument for the
+   probe.  */
+
+struct dtrace_probe_arg
+{
+  /* The type of the probe argument.  */
+  struct type *type;
+
+  /* A string describing the type.  */
+  char *type_str;
+
+  /* The argument converted to an internal GDB expression.  */
+  struct expression *expr;
+};
+
+typedef struct dtrace_probe_arg dtrace_probe_arg_s;
+DEF_VEC_O (dtrace_probe_arg_s);
+
+/* The following structure represents an enabler for a probe.  */
+
+struct dtrace_probe_enabler
+{
+  /* Program counter where the is-enabled probe is installed.  The
+     contents (nops, whatever...) stored at this address are
+     architecture dependent.  */
+  CORE_ADDR address;
+};
+
+typedef struct dtrace_probe_enabler dtrace_probe_enabler_s;
+DEF_VEC_O (dtrace_probe_enabler_s);
+
+/* The following structure represents a dtrace probe.  */
+
+struct dtrace_probe
+{
+  /* Generic information about the probe.  This must be the first
+     element of this struct, in order to maintain binary compatibility
+     with the `struct probe' and be able to fully abstract it.  */
+  struct probe p;
+
+  /* A probe can have zero or more arguments.  */
+  int probe_argc;
+  VEC (dtrace_probe_arg_s) *args;
+
+  /* A probe can have zero or more "enablers" associated with it.  */
+  VEC (dtrace_probe_enabler_s) *enablers;
+
+  /* Whether the expressions for the arguments have been built.  */
+  unsigned int args_expr_built : 1;
+};
+
+/* Implementation of the probe_is_linespec method.  */
+
+static int
+dtrace_probe_is_linespec (const char **linespecp)
+{
+  static const char *const keywords[] = { "-pdtrace", "-probe-dtrace", NULL };
+
+  return probe_is_linespec_by_keyword (linespecp, keywords);
+}
+
+/* DOF programs can contain an arbitrary number of sections of 26
+   different types.  In order to support DTrace USDT probes we only
+   need to handle a subset of these section types, fortunately.  These
+   section types are defined in the following enumeration.
+
+   See linux/dtrace/dof_defines.h for a complete list of section types
+   along with their values.  */
+
+enum dtrace_dof_sect_type
+{
+  /* Null section.  */
+  DTRACE_DOF_SECT_TYPE_NONE     = 0,
+  /* A dof_ecbdesc_t. */
+  DTRACE_DOF_SECT_TYPE_ECBDESC  = 3,
+  /* A string table.  */
+  DTRACE_DOF_SECT_TYPE_STRTAB   = 8,
+  /* A dof_provider_t  */
+  DTRACE_DOF_SECT_TYPE_PROVIDER = 15,
+  /* Array of dof_probe_t  */
+  DTRACE_DOF_SECT_TYPE_PROBES   = 16,
+  /* An array of probe arg mappings.  */
+  DTRACE_DOF_SECT_TYPE_PRARGS   = 17,
+  /* An array of probe arg offsets.  */
+  DTRACE_DOF_SECT_TYPE_PROFFS   = 18,
+  /* An array of probe is-enabled offsets.  */
+  DTRACE_DOF_SECT_TYPE_PRENOFFS = 26
+};
+
+/* The following collection of data structures map the structure of
+   DOF entities.  Again, we only cover the subset of DOF used to
+   implement USDT probes.
+
+   See linux/dtrace/dof.h header for a complete list of data
+   structures.  */
+
+/* Offsets to index the dofh_ident[] array defined below.  */
+
+enum dtrace_dof_ident
+{
+  /* First byte of the magic number.  */
+  DTRACE_DOF_ID_MAG0     = 0,
+  /* Second byte of the magic number.  */
+  DTRACE_DOF_ID_MAG1     = 1,
+  /* Third byte of the magic number.  */
+  DTRACE_DOF_ID_MAG2     = 2,
+  /* Fourth byte of the magic number.  */
+  DTRACE_DOF_ID_MAG3     = 3,
+  /* An enum_dof_encoding value.  */
+  DTRACE_DOF_ID_ENCODING = 5
+};
+
+/* Possible values for dofh_ident[DOF_ID_ENCODING].  */
+
+enum dtrace_dof_encoding
+{
+  /* The DOF program is little-endian.  */
+  DTRACE_DOF_ENCODE_LSB = 1,
+  /* The DOF program is big-endian.  */
+  DTRACE_DOF_ENCODE_MSB = 2
+};
+
+/* A DOF header, which describes the contents of a DOF program: number
+   of sections, size, etc.  */
+
+struct dtrace_dof_hdr
+{
+  /* Identification bytes (see above). */
+  uint8_t dofh_ident[16];
+  /* File attribute flags (if any). */
+  uint32_t dofh_flags;   
+  /* Size of file header in bytes. */
+  uint32_t dofh_hdrsize; 
+  /* Size of section header in bytes. */
+  uint32_t dofh_secsize; 
+  /* Number of section headers. */
+  uint32_t dofh_secnum;  
+  /* File offset of section headers. */
+  uint64_t dofh_secoff;  
+  /* File size of loadable portion. */
+  uint64_t dofh_loadsz;  
+  /* File size of entire DOF file. */
+  uint64_t dofh_filesz;  
+  /* Reserved for future use. */
+  uint64_t dofh_pad;     
+};
+
+/* A DOF section, whose contents depend on its type.  The several
+   supported section types are described in the enum
+   dtrace_dof_sect_type above.  */
+
+struct dtrace_dof_sect
+{
+  /* Section type (see the define above). */
+  uint32_t dofs_type;
+  /* Section data memory alignment. */
+  uint32_t dofs_align; 
+  /* Section flags (if any). */
+  uint32_t dofs_flags; 
+  /* Size of section entry (if table). */
+  uint32_t dofs_entsize;
+  /* DOF + offset points to the section data. */
+  uint64_t dofs_offset;
+  /* Size of section data in bytes.  */
+  uint64_t dofs_size;  
+};
+
+/* A DOF provider, which is the provider of a probe.  */
+
+struct dtrace_dof_provider
+{
+  /* Link to a DTRACE_DOF_SECT_TYPE_STRTAB section. */
+  uint32_t dofpv_strtab; 
+  /* Link to a DTRACE_DOF_SECT_TYPE_PROBES section. */
+  uint32_t dofpv_probes; 
+  /* Link to a DTRACE_DOF_SECT_TYPE_PRARGS section. */
+  uint32_t dofpv_prargs; 
+  /* Link to a DTRACE_DOF_SECT_TYPE_PROFFS section. */
+  uint32_t dofpv_proffs; 
+  /* Provider name string. */
+  uint32_t dofpv_name;   
+  /* Provider attributes. */
+  uint32_t dofpv_provattr;
+  /* Module attributes. */
+  uint32_t dofpv_modattr; 
+  /* Function attributes. */
+  uint32_t dofpv_funcattr;
+  /* Name attributes. */
+  uint32_t dofpv_nameattr;
+  /* Args attributes. */
+  uint32_t dofpv_argsattr;
+  /* Link to a DTRACE_DOF_SECT_PRENOFFS section. */
+  uint32_t dofpv_prenoffs;
+};
+
+/* A set of DOF probes and is-enabled probes sharing a base address
+   and several attributes.  The particular locations and attributes of
+   each probe are maintained in arrays in several other DOF sections.
+   See the comment in dtrace_process_dof_probe for details on how
+   these attributes are stored.  */
+
+struct dtrace_dof_probe
+{
+  /* Probe base address or offset. */
+  uint64_t dofpr_addr;   
+  /* Probe function string. */
+  uint32_t dofpr_func;   
+  /* Probe name string. */
+  uint32_t dofpr_name;   
+  /* Native argument type strings. */
+  uint32_t dofpr_nargv;  
+  /* Translated argument type strings. */
+  uint32_t dofpr_xargv;  
+  /* Index of first argument mapping. */
+  uint32_t dofpr_argidx; 
+  /* Index of first offset entry. */
+  uint32_t dofpr_offidx; 
+  /* Native argument count. */
+  uint8_t  dofpr_nargc;  
+  /* Translated argument count. */
+  uint8_t  dofpr_xargc;  
+  /* Number of offset entries for probe. */
+  uint16_t dofpr_noffs;  
+  /* Index of first is-enabled offset. */
+  uint32_t dofpr_enoffidx;
+  /* Number of is-enabled offsets. */
+  uint16_t dofpr_nenoffs;
+  /* Reserved for future use. */
+  uint16_t dofpr_pad1;   
+  /* Reserved for future use. */
+  uint32_t dofpr_pad2;   
+};
+
+/* DOF supports two different encodings: MSB (big-endian) and LSB
+   (little-endian).  The encoding is itself encoded in the DOF header.
+   The following function returns an unsigned value in the host
+   endianness.  */
+
+#define DOF_UINT(dof, field)						\
+  extract_unsigned_integer ((gdb_byte *) &(field),			\
+			    sizeof ((field)),				\
+			    (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \
+			      == DTRACE_DOF_ENCODE_MSB)			\
+			     ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE))
+
+/* The following macro applies a given byte offset to a DOF (a pointer
+   to a dtrace_dof_hdr structure) and returns the resulting
+   address.  */
+
+#define DTRACE_DOF_PTR(dof, offset) (&((char *) (dof))[(offset)])
+
+/* The following macro returns a pointer to the beginning of a given
+   section in a DOF object.  The section is referred to by its index
+   in the sections array.  */
+
+#define DTRACE_DOF_SECT(dof, idx)					\
+  ((struct dtrace_dof_sect *)						\
+   DTRACE_DOF_PTR ((dof),						\
+		   DOF_UINT ((dof), (dof)->dofh_secoff)			\
+		   + ((idx) * DOF_UINT ((dof), (dof)->dofh_secsize))))
+
+/* Helper function to examine the probe described by the given PROBE
+   and PROVIDER data structures and add it to the PROBESP vector.
+   STRTAB, OFFTAB, EOFFTAB and ARGTAB are pointers to tables in the
+   DOF program containing the attributes for the probe.  */
+
+static void
+dtrace_process_dof_probe (struct objfile *objfile,
+			  struct gdbarch *gdbarch, VEC (probe_p) **probesp,
+			  struct dtrace_dof_hdr *dof,
+			  struct dtrace_dof_probe *probe,
+			  struct dtrace_dof_provider *provider,
+			  char *strtab, char *offtab, char *eofftab,
+			  char *argtab, uint64_t strtab_size)
+{
+  int i, j, num_probes, num_enablers;
+  struct cleanup *cleanup;
+  VEC (dtrace_probe_enabler_s) *enablers;
+  char *p;
+
+  /* Each probe section can define zero or more probes of two
+     different types:
+
+     - probe->dofpr_noffs regular probes whose program counters are
+       stored in 32bit words starting at probe->dofpr_addr +
+       offtab[probe->dofpr_offidx].
+
+     - probe->dofpr_nenoffs is-enabled probes whose program counters
+       are stored in 32bit words starting at probe->dofpr_addr +
+       eofftab[probe->dofpr_enoffidx].
+
+     However is-enabled probes are not probes per-se, but an
+     optimization hack that is implemented in the kernel in a very
+     similar way than normal probes.  This is how we support
+     is-enabled probes on GDB:
+
+     - Our probes are always DTrace regular probes.
+
+     - Our probes can be associated with zero or more "enablers".  The
+       list of enablers is built from the is-enabled probes defined in
+       the Probe section.
+
+     - Probes having a non-empty list of enablers can be enabled or
+       disabled using the `enable probe' and `disable probe' commands
+       respectively.  The `Enabled' column in the output of `info
+       probes' will read `yes' if the enablers are activated, `no'
+       otherwise.
+
+     - Probes having an empty list of enablers are always enabled.
+       The `Enabled' column in the output of `info probes' will
+       read `always'.
+
+     It follows that if there are DTrace is-enabled probes defined for
+     some provider/name but no DTrace regular probes defined then the
+     GDB user wont be able to enable/disable these conditionals.  */
+
+  num_probes = DOF_UINT (dof, probe->dofpr_noffs);
+  if (num_probes == 0)
+    return;
+
+  /* Build the list of enablers for the probes defined in this Probe
+     DOF section.  */
+  enablers = NULL;
+  cleanup
+    = make_cleanup (VEC_cleanup (dtrace_probe_enabler_s), &enablers);
+  num_enablers = DOF_UINT (dof, probe->dofpr_nenoffs);
+  for (i = 0; i < num_enablers; i++)
+    {
+      struct dtrace_probe_enabler enabler;
+      uint32_t enabler_offset
+	= ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
+
+      enabler.address = DOF_UINT (dof, probe->dofpr_addr)
+	+ DOF_UINT (dof, enabler_offset);
+      VEC_safe_push (dtrace_probe_enabler_s, enablers, &enabler);
+    }
+
+  for (i = 0; i < num_probes; i++)
+    {
+      uint32_t probe_offset
+	= ((uint32_t *) offtab)[DOF_UINT (dof, probe->dofpr_offidx) + i];
+      struct dtrace_probe *ret
+	= obstack_alloc (&objfile->per_bfd->storage_obstack, sizeof (*ret));
+
+      ret->p.pops = &dtrace_probe_ops;
+      ret->p.arch = gdbarch;
+      ret->args_expr_built = 0;
+
+      /* Set the provider and the name of the probe.  */
+      ret->p.provider
+	= xstrdup (strtab + DOF_UINT (dof, provider->dofpv_name));
+      ret->p.name = xstrdup (strtab + DOF_UINT (dof, probe->dofpr_name));
+
+      /* The probe address.  */
+      ret->p.address
+	= DOF_UINT (dof, probe->dofpr_addr) + DOF_UINT (dof, probe_offset);
+
+      /* Number of arguments in the probe.  */
+      ret->probe_argc = DOF_UINT (dof, probe->dofpr_nargc);
+
+      /* Store argument type descriptions.  A description of the type
+         of the argument is in the (J+1)th null-terminated string
+         starting at 'strtab' + 'probe->dofpr_nargv'.  */
+      ret->args = NULL;
+      p = strtab + DOF_UINT (dof, probe->dofpr_nargv);
+      for (j = 0; j < ret->probe_argc; j++)
+	{
+	  struct dtrace_probe_arg arg;
+	  struct expression *expr;
+
+	  arg.type_str = xstrdup (p);
+
+	  /* Use strtab_size as a sentinel.  */
+	  while (*p++ != '\0' && p - strtab < strtab_size);
+
+	  /* Try to parse a type expression from the type string.  If
+	     this does not work then we set the type to `long
+	     int'.  */
+          arg.type = builtin_type (gdbarch)->builtin_long;
+	  expr = parse_expression (arg.type_str);
+	  if (expr->elts[0].opcode == OP_TYPE)
+	    arg.type = expr->elts[1].type;
+
+	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
+	}
+
+      /* Add the vector of enablers to this probe, if any.  */
+      ret->enablers = VEC_copy (dtrace_probe_enabler_s, enablers);
+
+      /* Successfully created probe.  */
+      VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
+    }
+
+  do_cleanups (cleanup);
+}
+
+/* Helper function to collect the probes described in the DOF program
+   whose header is pointed by DOF and add them to the PROBESP vector.
+   SECT is the ELF section containing the DOF program and OBJFILE is
+   its containing object file.  */
+
+static void
+dtrace_process_dof (asection *sect, struct objfile *objfile,
+		    VEC (probe_p) **probesp, struct dtrace_dof_hdr *dof)
+{
+  bfd *abfd = objfile->obfd;
+  int size = bfd_get_arch_size (abfd) / 8;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  struct dtrace_dof_sect *section;
+  int i;
+
+  /* The first step is to check for the DOF magic number.  If no valid
+     DOF data is found in the section then a complaint is issued to
+     the user and the section skipped.  */
+  if (dof->dofh_ident[DTRACE_DOF_ID_MAG0] != 0x7F
+      || dof->dofh_ident[DTRACE_DOF_ID_MAG1] != 'D'
+      || dof->dofh_ident[DTRACE_DOF_ID_MAG2] != 'O'
+      || dof->dofh_ident[DTRACE_DOF_ID_MAG3] != 'F')
+    goto invalid_dof_data;
+
+  /* Make sure the encoding mark is either DTRACE_DOF_ENCODE_LSB or
+     DTRACE_DOF_ENCODE_MSB.  */
+  if (dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_LSB
+      && dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_MSB)
+    goto invalid_dof_data;
+
+  /* Make sure this DOF is not an enabling DOF, i.e. there are no ECB
+     Description sections.  */
+  section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
+						       DOF_UINT (dof, dof->dofh_secoff));
+  for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
+    if (section->dofs_type == DTRACE_DOF_SECT_TYPE_ECBDESC)
+      return;
+
+  /* Iterate over any section of type Provider and extract the probe
+     information from them.  If there are no "provider" sections on
+     the DOF then we just return.  */
+  section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
+						       DOF_UINT (dof, dof->dofh_secoff));
+  for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
+    if (DOF_UINT (dof, section->dofs_type) == DTRACE_DOF_SECT_TYPE_PROVIDER)
+      {
+	struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
+	  DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
+	struct dtrace_dof_sect *strtab_s
+	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_strtab));
+	struct dtrace_dof_sect *probes_s
+	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_probes));
+	struct dtrace_dof_sect *args_s
+	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prargs));
+	struct dtrace_dof_sect *offsets_s
+	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_proffs));
+	struct dtrace_dof_sect *eoffsets_s
+	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prenoffs));
+	char *strtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, strtab_s->dofs_offset));
+	char *offtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, offsets_s->dofs_offset));
+	char *eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
+	char *argtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, args_s->dofs_offset));
+	unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
+	int num_probes;
+
+	/* Very, unlikely, but could crash gdb if not handled
+	   properly.  */
+	if (entsize == 0)
+	  goto invalid_dof_data;
+
+	num_probes = DOF_UINT (dof, probes_s->dofs_size) / entsize;
+
+	for (i = 0; i < num_probes; i++)
+	  {
+	    struct dtrace_dof_probe *probe = (struct dtrace_dof_probe *)
+	      DTRACE_DOF_PTR (dof, DOF_UINT (dof, probes_s->dofs_offset)
+			      + (i * DOF_UINT (dof, probes_s->dofs_entsize)));
+
+	    dtrace_process_dof_probe (objfile,
+				      gdbarch, probesp,
+				      dof, probe,
+				      provider, strtab, offtab, eofftab, argtab,
+				      DOF_UINT (dof, strtab_s->dofs_size));
+	  }
+      }
+
+  return;
+	  
+ invalid_dof_data:
+  complaint (&symfile_complaints,
+	     _("skipping section '%s' which does not contain valid DOF data."),
+	     sect->name);
+}
+
+/* Helper function to build the GDB internal expressiosn that, once
+   evaluated, will calculate the values of the arguments of a given
+   PROBE.  */
+
+static void
+dtrace_build_arg_exprs (struct dtrace_probe *probe,
+			struct gdbarch *gdbarch)
+{
+  struct parser_state pstate;
+  struct dtrace_probe_arg *arg;
+  int i;
+
+  probe->args_expr_built = 1;
+
+  /* Iterate over the arguments in the probe and build the
+     corresponding GDB internal expression that will generate the
+     value of the argument when executed at the PC of the probe.  */
+  for (i = 0; i < probe->probe_argc; i++)
+    {
+      struct cleanup *back_to;
+
+      arg = VEC_index (dtrace_probe_arg_s, probe->args, i);
+
+      /* Initialize the expression buffer in the parser state.  The
+	 language does not matter, since we are using our own
+	 parser.  */
+      initialize_expout (&pstate, 10, current_language, gdbarch);
+      back_to = make_cleanup (free_current_contents, &pstate.expout);
+
+      /* The argument value, which is ABI dependent and casted to
+	 `long int'.  */
+      gdbarch_dtrace_parse_probe_argument (gdbarch, &pstate, i);
+
+      discard_cleanups (back_to);
+
+      /* Casting to the expected type, but only if the type was
+	 recognized at probe load time.  Otherwise the argument will
+	 be evaluated as the long integer passed to the probe.  */
+      if (arg->type != NULL)
+	{
+	  write_exp_elt_opcode (&pstate, UNOP_CAST);
+	  write_exp_elt_type   (&pstate, arg->type);
+	  write_exp_elt_opcode (&pstate, UNOP_CAST);
+	}     
+
+      reallocate_expout (&pstate);
+      arg->expr = pstate.expout;
+      prefixify_expression (arg->expr);
+    }
+}
+
+/* Helper function to return the Nth argument of a given PROBE.  */
+
+static struct dtrace_probe_arg *
+dtrace_get_arg (struct dtrace_probe *probe, unsigned n,
+		struct gdbarch *gdbarch)
+{
+  if (!probe->args_expr_built)
+    dtrace_build_arg_exprs (probe, gdbarch);
+
+  return VEC_index (dtrace_probe_arg_s, probe->args, n);
+}
+
+/* Implementation of the get_probes method.  */
+
+static void
+dtrace_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
+{
+  bfd *abfd = objfile->obfd;
+  asection *sect = NULL;
+
+  /* Do nothing in case this is a .debug file, instead of the objfile
+     itself.  */
+  if (objfile->separate_debug_objfile_backlink != NULL)
+    return;
+
+  /* Iterate over the sections in OBJFILE looking for DTrace
+     information.  */
+  for (sect = abfd->sections; sect != NULL; sect = sect->next)
+    {
+      if (elf_section_data (sect)->this_hdr.sh_type == SHT_SUNW_dof)
+	{
+	  struct dtrace_dof_hdr *dof;
+
+	  /* Read the contents of the DOF section and then process it to
+	     extract the information of any probe defined into it.  */
+	  if (!bfd_malloc_and_get_section (abfd, sect, (bfd_byte **) &dof))
+	    complaint (&symfile_complaints,
+		       _("could not obtain the contents of"
+			 "section '%s' in objfile `%s'."),
+		       sect->name, abfd->filename);
+      
+	  dtrace_process_dof (sect, objfile, probesp, dof);
+	  xfree (dof);
+	}
+    }
+}
+
+/* Helper function to determine whether a given probe is "enabled" or
+   "disabled".  A disabled probe is a probe in which one or more
+   enablers are disabled.  */
+
+static int
+dtrace_probe_is_enabled (struct dtrace_probe *probe)
+{
+  int i;
+  struct gdbarch *gdbarch = probe->p.arch;
+  struct dtrace_probe_enabler *enabler;
+
+  for (i = 0;
+       VEC_iterate (dtrace_probe_enabler_s, probe->enablers, i, enabler);
+       i++)
+    if (!gdbarch_dtrace_probe_is_enabled (gdbarch, enabler->address))
+      return 0;
+
+  return 1;
+}
+
+/* Implementation of the get_probe_address method.  */
+
+static CORE_ADDR
+dtrace_get_probe_address (struct probe *probe, struct objfile *objfile)
+{
+  gdb_assert (probe->pops == &dtrace_probe_ops);
+  return probe->address + ANOFFSET (objfile->section_offsets,
+				    SECT_OFF_DATA (objfile));
+}
+
+/* Implementation of the get_probe_argument_count method.  */
+
+static unsigned
+dtrace_get_probe_argument_count (struct probe *probe_generic,
+				 struct frame_info *frame)
+{
+  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+  return dtrace_probe->probe_argc;
+}
+
+/* Implementation of the can_evaluate_probe_arguments method.  */
+
+static int
+dtrace_can_evaluate_probe_arguments (struct probe *probe_generic)
+{
+  struct gdbarch *gdbarch = probe_generic->arch;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+  return gdbarch_dtrace_parse_probe_argument_p (gdbarch);
+}
+
+/* Implementation of the evaluate_probe_argument method.  */
+
+static struct value *
+dtrace_evaluate_probe_argument (struct probe *probe_generic, unsigned n,
+				struct frame_info *frame)
+{
+  struct gdbarch *gdbarch = probe_generic->arch;
+  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+  struct dtrace_probe_arg *arg;
+  int pos = 0;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+  arg = dtrace_get_arg (dtrace_probe, n, gdbarch);
+  return evaluate_subexp_standard (arg->type, arg->expr, &pos, EVAL_NORMAL);
+}
+
+/* Implementation of the compile_to_ax method.  */
+
+static void
+dtrace_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr,
+		      struct axs_value *value, unsigned n)
+{
+  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+  struct dtrace_probe_arg *arg;
+  union exp_element *pc;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+  arg = dtrace_get_arg (dtrace_probe, n, expr->gdbarch);
+
+  pc = arg->expr->elts;
+  gen_expr (arg->expr, &pc, expr, value);
+
+  require_rvalue (expr, value);
+  value->type = arg->type;
+}
+
+/* Implementation of the probe_destroy method.  */
+
+static void
+dtrace_probe_destroy (struct probe *probe_generic)
+{
+  struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
+  struct dtrace_probe_arg *arg;
+  int i;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+  for (i = 0; VEC_iterate (dtrace_probe_arg_s, probe->args, i, arg); i++)
+    {
+      xfree (arg->type_str);
+      xfree (arg->expr);
+    }
+
+  VEC_free (dtrace_probe_enabler_s, probe->enablers);
+  VEC_free (dtrace_probe_arg_s, probe->args);
+}
+
+/* Implementation of the type_name method.  */
+
+static const char *
+dtrace_type_name (struct probe *probe_generic)
+{
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+  return "dtrace";
+}
+
+/* Implementation of the gen_info_probes_table_header method.  */
+
+static void
+dtrace_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
+{
+  info_probe_column_s dtrace_probe_column;
+
+  dtrace_probe_column.field_name = "enabled";
+  dtrace_probe_column.print_name = _("Enabled");
+
+  VEC_safe_push (info_probe_column_s, *heads, &dtrace_probe_column);
+}
+
+/* Implementation of the gen_info_probes_table_values method.  */
+
+static void
+dtrace_gen_info_probes_table_values (struct probe *probe_generic,
+				     VEC (const_char_ptr) **ret)
+{
+  struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
+  const char *val = NULL;
+
+  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+  if (VEC_empty (dtrace_probe_enabler_s, probe->enablers))
+    val = "always";
+  else if (!gdbarch_dtrace_probe_is_enabled_p (probe_generic->arch))
+    val = "unknown";
+  else if (dtrace_probe_is_enabled (probe))
+    val = "yes";
+  else
+    val = "no";
+
+  VEC_safe_push (const_char_ptr, *ret, val);
+}
+
+/* Implementation of the enable_probe method.  */
+
+static void
+dtrace_enable_probe (struct probe *probe)
+{
+  struct gdbarch *gdbarch = probe->arch;
+  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
+  struct dtrace_probe_enabler *enabler;
+  int i;
+
+  gdb_assert (probe->pops == &dtrace_probe_ops);
+
+  /* Enabling a dtrace probe implies patching the text section of the
+     running process, so make sure the inferior is indeed running.  */
+  if (ptid_equal (inferior_ptid, null_ptid))
+    error (_("No inferior running"));
+
+  /* Fast path.  */
+  if (dtrace_probe_is_enabled (dtrace_probe))
+    return;
+
+  /* Iterate over all defined enabler in the given probe and enable
+     them all using the corresponding gdbarch hook.  */
+
+  for (i = 0;
+       VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
+       i++)
+    if (gdbarch_dtrace_enable_probe_p (gdbarch))
+      gdbarch_dtrace_enable_probe (gdbarch, enabler->address);
+}
+
+
+/* Implementation of the disable_probe method.  */
+
+static void
+dtrace_disable_probe (struct probe *probe)
+{
+  struct gdbarch *gdbarch = probe->arch;
+  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
+  struct dtrace_probe_enabler *enabler;
+  int i;
+
+  gdb_assert (probe->pops == &dtrace_probe_ops);
+
+  /* Disabling a dtrace probe implies patching the text section of the
+     running process, so make sure the inferior is indeed running.  */
+  if (ptid_equal (inferior_ptid, null_ptid))
+    error (_("No inferior running"));
+
+  /* Fast path.  */
+  if (!dtrace_probe_is_enabled (dtrace_probe))
+    return;
+
+  /* Are we trying to disable a probe that does not have any enabler
+     associated?  */
+  if (VEC_empty (dtrace_probe_enabler_s, dtrace_probe->enablers))
+    error (_("Probe %s:%s cannot be disabled."), probe->provider, probe->name);
+
+  /* Iterate over all defined enabler in the given probe and disable
+     them all using the corresponding gdbarch hook.  */
+
+  for (i = 0;
+       VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
+       i++)
+    {
+      if (gdbarch_dtrace_disable_probe_p (gdbarch))
+	gdbarch_dtrace_disable_probe (gdbarch, enabler->address);
+    }
+}
+
+/* DTrace probe_ops.  */
+
+static const struct probe_ops dtrace_probe_ops =
+{
+  dtrace_probe_is_linespec,
+  dtrace_get_probes,
+  dtrace_get_probe_address,
+  dtrace_get_probe_argument_count,
+  dtrace_can_evaluate_probe_arguments,
+  dtrace_evaluate_probe_argument,
+  dtrace_compile_to_ax,
+  NULL, /* set_semaphore  */
+  NULL, /* clear_semaphore  */
+  dtrace_probe_destroy,
+  dtrace_type_name,
+  dtrace_gen_info_probes_table_header,
+  dtrace_gen_info_probes_table_values,
+  dtrace_enable_probe,
+  dtrace_disable_probe
+};
+
+/* Implementation of the `info probes dtrace' command.  */
+
+static void
+info_probes_dtrace_command (char *arg, int from_tty)
+{
+  info_probes_for_ops (arg, from_tty, &dtrace_probe_ops);
+}
+
+void _initialize_dtrace_probe (void);
+
+void
+_initialize_dtrace_probe (void)
+{
+  VEC_safe_push (probe_ops_cp, all_probe_ops, &dtrace_probe_ops);
+
+  add_cmd ("dtrace", class_info, info_probes_dtrace_command,
+	   _("\
+Show information about DTrace static probes.\n\
+Usage: info probes dtrace [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name."),
+	   info_probes_cmdlist_get ());
+}
-- 
1.7.10.4

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

* [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (7 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-17  1:12   ` Sergio Durigan Junior
  2015-02-16 13:20 ` [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
  2015-02-17  1:57 ` Sergio Durigan Junior
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

A "probe type" (backend for the probe abstraction implemented in
probe.[ch]) can extend the information printed by `info probes' by
defining additional columns.  This means that when `info probes' is
used to print all the probes regardless of their types, some of the
columns will be "not applicable" to some of the probes (like, say, the
Semaphore column only makes sense for SystemTap probes).  This patch
makes `info probes' fill these slots with "n/a" marks (currently it
breaks the table) and not include headers for which no actual probe
has been found in the list of defined probes.

This patch also adds support for a new generic column "Type", that
displays the type of each probe.  SystemTap probes identify themselves
as "stap" probes.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* probe.c (print_ui_out_not_applicables): New function.
	(exists_probe_with_pops): Likewise.
	(info_probes_for_ops): Do not include column headers for probe
	types for which no probe has been actually found on any object.
	Also invoke `print_ui_out_not_applicables' in order to match the
	column rows with the header when probes of several types are
	listed.
	Print the "Type" column.
	* probe.h (probe_ops): Added a new probe operation `type_name'.
	* stap-probe.c (stap_probe_ops): Add `stap_type_name'.
	(stap_type_name): New function.
---
 gdb/ChangeLog    |   14 ++++++++++
 gdb/probe.c      |   76 +++++++++++++++++++++++++++++++++++++++++++++++-------
 gdb/probe.h      |    6 +++++
 gdb/stap-probe.c |   12 ++++++++-
 4 files changed, 97 insertions(+), 11 deletions(-)

diff --git a/gdb/probe.c b/gdb/probe.c
index 56b5fc1..be3e656 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -410,6 +410,31 @@ gen_ui_out_table_header_info (VEC (bound_probe_s) *probes,
   do_cleanups (c);
 }
 
+/* Helper function to print not-applicable strings for all the extra
+   columns defined in a probe_ops.  */
+
+static void
+print_ui_out_not_applicables (const struct probe_ops *pops)
+{
+  struct cleanup *c;
+  VEC (info_probe_column_s) *headings = NULL;
+  info_probe_column_s *column;
+  int ix;
+
+  if (pops->gen_info_probes_table_header == NULL)
+    return;
+
+  c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+  pops->gen_info_probes_table_header (&headings);
+
+  for (ix = 0;
+       VEC_iterate (info_probe_column_s, headings, ix, column);
+       ++ix)
+    ui_out_field_string (current_uiout, column->field_name, _("n/a"));
+
+  do_cleanups (c);
+}
+
 /* Helper function to print extra information about a probe and an objfile
    represented by PROBE.  */
 
@@ -482,6 +507,23 @@ get_number_extra_fields (const struct probe_ops *pops)
   return n;
 }
 
+/* Helper function that returns 1 if there is a probe in PROBES
+   featuring the given POPS.  It returns 0 otherwise.  */
+
+static int
+exists_probe_with_pops (VEC (bound_probe_s) *probes,
+			const struct probe_ops *pops)
+{
+  struct bound_probe *probe;
+  int ix;
+
+  for (ix = 0; VEC_iterate (bound_probe_s, probes, ix, probe); ++ix)
+    if (probe->probe->pops == pops)
+      return 1;
+
+  return 0;
+}
+
 /* See comment in probe.h.  */
 
 void
@@ -497,6 +539,7 @@ info_probes_for_ops (const char *arg, int from_tty,
   size_t size_name = strlen ("Name");
   size_t size_objname = strlen ("Object");
   size_t size_provider = strlen ("Provider");
+  size_t size_type = strlen ("Type");
   struct bound_probe *probe;
   struct gdbarch *gdbarch = get_current_arch ();
 
@@ -517,6 +560,9 @@ info_probes_for_ops (const char *arg, int from_tty,
 	}
     }
 
+  probes = collect_probes (objname, provider, probe_name, pops);
+  make_cleanup (VEC_cleanup (probe_p), &probes);
+
   if (pops == NULL)
     {
       const struct probe_ops *po;
@@ -529,18 +575,18 @@ info_probes_for_ops (const char *arg, int from_tty,
 
 	 To do that, we iterate over all probe_ops, querying each one about
 	 its extra fields, and incrementing `ui_out_extra_fields' to reflect
-	 that number.  */
+	 that number.  But note that we ignore the probe_ops for which no probes
+         are defined with the given search criteria.  */
 
       for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
-	ui_out_extra_fields += get_number_extra_fields (po);
+	if (exists_probe_with_pops (probes, po))
+	  ui_out_extra_fields += get_number_extra_fields (po);
     }
   else
     ui_out_extra_fields = get_number_extra_fields (pops);
 
-  probes = collect_probes (objname, provider, probe_name, pops);
-  make_cleanup (VEC_cleanup (probe_p), &probes);
   make_cleanup_ui_out_table_begin_end (current_uiout,
-				       4 + ui_out_extra_fields,
+				       5 + ui_out_extra_fields,
 				       VEC_length (bound_probe_s, probes),
 				       "StaticProbes");
 
@@ -552,15 +598,19 @@ info_probes_for_ops (const char *arg, int from_tty,
   /* What's the size of an address in our architecture?  */
   size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
 
-  /* Determining the maximum size of each field (`provider', `name' and
-     `objname').  */
+  /* Determining the maximum size of each field (`type', `provider',
+     `name' and `objname').  */
   for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
     {
+      const char *probe_type = probe->probe->pops->type_name (probe->probe);
+
+      size_type = max (strlen (probe_type), size_type);
       size_name = max (strlen (probe->probe->name), size_name);
       size_provider = max (strlen (probe->probe->provider), size_provider);
       size_objname = max (strlen (objfile_name (probe->objfile)), size_objname);
     }
 
+  ui_out_table_header (current_uiout, size_type, ui_left, "type", _("Type"));
   ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
 		       _("Provider"));
   ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
@@ -571,10 +621,12 @@ info_probes_for_ops (const char *arg, int from_tty,
       const struct probe_ops *po;
       int ix;
 
-      /* We have to generate the table header for each new probe type that we
-	 will print.  */
+      /* We have to generate the table header for each new probe type
+	 that we will print.  Note that this excludes probe types not
+	 having any defined probe with the search criteria.  */
       for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
-	gen_ui_out_table_header_info (probes, po);
+	if (exists_probe_with_pops (probes, po))
+	  gen_ui_out_table_header_info (probes, po);
     }
   else
     gen_ui_out_table_header_info (probes, pops);
@@ -586,9 +638,11 @@ info_probes_for_ops (const char *arg, int from_tty,
   for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
     {
       struct cleanup *inner;
+      const char *probe_type = probe->probe->pops->type_name (probe->probe);
 
       inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
 
+      ui_out_field_string (current_uiout, "type",probe_type);
       ui_out_field_string (current_uiout, "provider", probe->probe->provider);
       ui_out_field_string (current_uiout, "name", probe->probe->name);
       ui_out_field_core_addr (current_uiout, "addr",
@@ -604,6 +658,8 @@ info_probes_for_ops (const char *arg, int from_tty,
 	       ++ix)
 	    if (probe->probe->pops == po)
 	      print_ui_out_info (probe->probe);
+	    else if (exists_probe_with_pops (probes, po))
+	      print_ui_out_not_applicables (po);
 	}
       else
 	print_ui_out_info (probe->probe);
diff --git a/gdb/probe.h b/gdb/probe.h
index 1dd582d..5df1976 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -113,6 +113,12 @@ struct probe_ops
 
     void (*destroy) (struct probe *probe);
 
+    /* Return a pointer to a name identifying the probe type.  This is
+       the string that will be displayed in the "Type" column of the
+       `info probes' command.  */
+
+    const char *(*type_name) (struct probe *probe);
+
     /* Function responsible for providing the extra fields that will be
        printed in the `info probes' command.  It should fill HEADS
        with whatever extra fields it needs.  If the backend doesn't need
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index d7d9cf1..e534b6d 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1703,6 +1703,15 @@ stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
     }
 }
 
+/* Implementation of the type_name method.  */
+
+static const char *
+stap_type_name (struct probe *probe)
+{
+  gdb_assert (probe->pops == &stap_probe_ops);
+  return "stap";
+}
+
 static int
 stap_probe_is_linespec (const char **linespecp)
 {
@@ -1743,7 +1752,7 @@ stap_gen_info_probes_table_values (struct probe *probe_generic,
 /* SystemTap probe_ops.  */
 
 static const struct probe_ops stap_probe_ops =
-{
+  {
   stap_probe_is_linespec,
   stap_get_probes,
   stap_get_probe_address,
@@ -1754,6 +1763,7 @@ static const struct probe_ops stap_probe_ops =
   stap_set_semaphore,
   stap_clear_semaphore,
   stap_probe_destroy,
+  stap_type_name,
   stap_gen_info_probes_table_header,
   stap_gen_info_probes_table_values,
 };
-- 
1.7.10.4

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

* [PATCH V4 0/9] Add support for DTrace USDT probes to gdb
@ 2015-02-02 10:57 Jose E. Marchesi
  2015-02-02 10:57 ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
                   ` (10 more replies)
  0 siblings, 11 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

[Changes from V3:
- Added some missing spaces after periods in the documentation patch.
  Spotted by Eli.
- Sort ChangeLog entries so they reflect the changes in the same order
  than the diffs.
- Use transformed tool names in the pdtrace script, which is now
  processed through configure.  Introduce a new GDB_AC_TRANSFORM macro
  to avoid repeating a code idiom and use it to define both
  GDB_TRANSFORM_NAME and GCORE_TRANSFORM_NAME in the main
  configure.ac.
- Copyright year updated to 2015 in new files introduces by the patch
  series.]

This patch series introduces support in GDB for a new type of probe:
DTrace USDT probes.

The first three patches do some changes to the existing probe.[ch]
code, fixing some minor problems associated to support several probe
types, having several probes of different types defined in the same
object and supporting the notion of enabling and disabling probes.

The rest of the patches are the implementation of the new probe type,
including target support for x86_64 targets, a testsuite and
documentation.

Tested on x86_64-*-linux-gnu.
No visible regressions.

Jose E. Marchesi (9):
  Adapt `info probes' to support printing probes of different types.
  Move `compute_probe_arg' and `compile_probe_arg' to probe.c
  New commands `enable probe' and `disable probe'.
  New gdbarch functions: dtrace_parse_probe_argument,
    dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
  New probe type: DTrace USDT probes.
  Support for DTrace USDT probes in x86_64 targets.
  Simple testsuite for DTrace USDT probes.
  Documentation for DTrace USDT probes.
  Announce the DTrace USDT probes support in NEWS.

 gdb/ChangeLog                           |  120 ++++
 gdb/Makefile.in                         |    4 +-
 gdb/NEWS                                |    3 +
 gdb/acinclude.m4                        |    3 +
 gdb/amd64-linux-tdep.c                  |  148 +++++
 gdb/breakpoint.c                        |    3 +-
 gdb/configure                           |   26 +-
 gdb/configure.ac                        |   16 +-
 gdb/doc/ChangeLog                       |   13 +
 gdb/doc/gdb.texinfo                     |   85 ++-
 gdb/dtrace-probe.c                      |  909 +++++++++++++++++++++++++++
 gdb/gdbarch.c                           |  128 ++++
 gdb/gdbarch.h                           |   36 ++
 gdb/gdbarch.sh                          |   16 +
 gdb/probe.c                             |  338 +++++++++-
 gdb/probe.h                             |   18 +
 gdb/stap-probe.c                        |  123 +---
 gdb/testsuite/ChangeLog                 |   18 +
 gdb/testsuite/aclocal.m4                |    1 +
 gdb/testsuite/configure                 |   62 ++
 gdb/testsuite/configure.ac              |    9 +
 gdb/testsuite/gdb.base/dtrace-probe.c   |   38 ++
 gdb/testsuite/gdb.base/dtrace-probe.d   |   21 +
 gdb/testsuite/gdb.base/dtrace-probe.exp |  106 ++++
 gdb/testsuite/gdb.base/stap-probe.exp   |    2 +-
 gdb/testsuite/lib/dtrace.exp            |   71 +++
 gdb/testsuite/lib/pdtrace.in            | 1033 +++++++++++++++++++++++++++++++
 27 files changed, 3170 insertions(+), 180 deletions(-)
 create mode 100644 gdb/dtrace-probe.c
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
 create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
 create mode 100644 gdb/testsuite/lib/dtrace.exp
 create mode 100755 gdb/testsuite/lib/pdtrace.in

-- 
1.7.10.4

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

* [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS.
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (4 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
@ 2015-02-02 10:57 ` Jose E. Marchesi
  2015-02-02 16:03   ` Eli Zaretskii
  2015-02-02 10:57 ` [PATCH V4 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 10:57 UTC (permalink / raw)
  To: gdb-patches

This patch simply adds a small entry to `Changes since GDB 7.8' announcing the
support for dtrace probes.

gdb/ChangeLog:

2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* NEWS: Announce the support for DTrace SDT probes.
---
 gdb/ChangeLog |    4 ++++
 gdb/NEWS      |    3 +++
 2 files changed, 7 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index f19577a..9d21e32 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -163,6 +163,9 @@ VAX running Ultrix 			vax-*-ultrix*
   and "assf"), have been removed.  Use the "sharedlibrary" command, or
   its alias "share", instead.
 
+* GDB now has support for DTrace USDT (Userland Static Defined
+  Tracing) probes.  The supported targets are x86_64-*-linux-gnu.
+     
 *** Changes in GDB 7.8
 
 * New command line options
-- 
1.7.10.4

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

* Re: [PATCH V4 7/9] Simple testsuite for DTrace USDT probes.
  2015-02-02 10:57 ` [PATCH V4 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
@ 2015-02-02 11:18   ` Jose E. Marchesi
  2015-02-17  1:53   ` Sergio Durigan Junior
  1 sibling, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 11:18 UTC (permalink / raw)
  To: gdb-patches


Sorry, I forgot to git add the gdb/transform.m4 file.  This is the
missing bit.

diff --git a/gdb/transform.m4 b/gdb/transform.m4
new file mode 100644
index 0000000..d9079af
--- /dev/null
+++ b/gdb/transform.m4
@@ -0,0 +1,23 @@
+# Copyright (C) 2015 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# GDB_AC_TRANSFORM([PROGRAM], [VAR])
+#
+# Transform a tool name to get the installed name of PROGRAM and store
+# it in the output variable VAR.
+#
+# This macro uses the SED command stored in $program_transform_name,
+# but it undoes the Makefile-like escaping of $s performed by
+# AC_ARG_PROGRAM.
+
+AC_DEFUN([GDB_AC_TRANSFORM], [
+  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/[\\$][\\$]/\\$/g'`
+  $2=`echo $1 | sed -e "$gdb_ac_transform"`
+  if test "x$$2" = x; then
+     $2=$1
+  fi
+  AC_SUBST($2)
+])

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

* Re: [PATCH V4 3/9] New commands `enable probe' and `disable probe'.
  2015-02-02 10:57 ` [PATCH V4 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
@ 2015-02-02 16:01   ` Eli Zaretskii
  2015-02-17  1:54   ` Sergio Durigan Junior
  1 sibling, 0 replies; 51+ messages in thread
From: Eli Zaretskii @ 2015-02-02 16:01 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

> From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
> Date: Mon,  2 Feb 2015 12:02:42 +0100
> 
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index aee17d3..4ab0bba 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -5011,6 +5011,35 @@ given, all object files are considered.
>  List the available static probes, from all types.
>  @end table
>  
> +@cindex enabling and disabling probes
> +Some probe points can be enabled and/or disabled.  The effect of
> +enabling or disabling a probe depends on the type of probe being
> +handled.  @code{SystemTap} probes cannot be disabled.
> +
> +You can enable (or disable) one or more probes using the following
> +commands, with optional arguments:
> +
> +@table @code
> +@kindex enable probes
> +@item enable probes @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 enable.  If omitted,
> +all probes from all providers are enabled.
> +
> +If given, @var{name} is a regular expression to match against probe
> +names when selecting which probes to enable.  If omitted, probe names
> +are not considered when deciding whether to enable 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.

OK for the documentation part.

Thanks.

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

* Re: [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS.
  2015-02-02 10:57 ` [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
@ 2015-02-02 16:03   ` Eli Zaretskii
  0 siblings, 0 replies; 51+ messages in thread
From: Eli Zaretskii @ 2015-02-02 16:03 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

> From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
> Date: Mon,  2 Feb 2015 12:02:48 +0100
> 
> This patch simply adds a small entry to `Changes since GDB 7.8' announcing the
> support for dtrace probes.
> 
> gdb/ChangeLog:
> 
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
> 
> 	* NEWS: Announce the support for DTrace SDT probes.
> ---
>  gdb/ChangeLog |    4 ++++
>  gdb/NEWS      |    3 +++
>  2 files changed, 7 insertions(+)

OK, thanks.

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

* Re: [PATCH V4 8/9] Documentation for DTrace USDT probes.
  2015-02-02 10:57 ` [PATCH V4 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
@ 2015-02-02 16:03   ` Eli Zaretskii
  2015-02-02 19:47     ` Jose E. Marchesi
  0 siblings, 1 reply; 51+ messages in thread
From: Eli Zaretskii @ 2015-02-02 16:03 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

> From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
> Date: Mon,  2 Feb 2015 12:02:47 +0100
> 
> This patch modifies the `Static Probe Points' section on the GDB
> manual in order to cover the support for DTrace USDT probes, in
> addition to SystemTap SDT probes.

Did anything change here since the previous version?

Anyway, this is OK.  Thanks.

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

* Re: [PATCH V4 8/9] Documentation for DTrace USDT probes.
  2015-02-02 16:03   ` Eli Zaretskii
@ 2015-02-02 19:47     ` Jose E. Marchesi
  0 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-02 19:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches


Hi Eli.

    > From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
    > Date: Mon,  2 Feb 2015 12:02:47 +0100
    > 
    > This patch modifies the `Static Probe Points' section on the GDB
    > manual in order to cover the support for DTrace USDT probes, in
    > addition to SystemTap SDT probes.
    
    Did anything change here since the previous version?

Yes.  These are the problems that you spotted and that were fixed in
this version of the patch series:

> -handled.  @code{SystemTap} probes cannot be disabled.
> +handled. Some @code{DTrace} probes can be enabled or
           ^^
Two spaces here, please.

> +disabled,but @code{SystemTap} probes cannot be disabled.
            ^
One space here, please.

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

* Re: [PATCH V4 0/9] Add support for DTrace USDT probes to gdb
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (8 preceding siblings ...)
  2015-02-02 10:57 ` [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
@ 2015-02-16 13:20 ` Jose E. Marchesi
  2015-02-17  1:57 ` Sergio Durigan Junior
  10 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-16 13:20 UTC (permalink / raw)
  To: gdb-patches


ping

    [Changes from V3:
    - Added some missing spaces after periods in the documentation patch.
      Spotted by Eli.
    - Sort ChangeLog entries so they reflect the changes in the same order
      than the diffs.
    - Use transformed tool names in the pdtrace script, which is now
      processed through configure.  Introduce a new GDB_AC_TRANSFORM macro
      to avoid repeating a code idiom and use it to define both
      GDB_TRANSFORM_NAME and GCORE_TRANSFORM_NAME in the main
      configure.ac.
    - Copyright year updated to 2015 in new files introduces by the patch
      series.]
    
    This patch series introduces support in GDB for a new type of probe:
    DTrace USDT probes.
    
    The first three patches do some changes to the existing probe.[ch]
    code, fixing some minor problems associated to support several probe
    types, having several probes of different types defined in the same
    object and supporting the notion of enabling and disabling probes.
    
    The rest of the patches are the implementation of the new probe type,
    including target support for x86_64 targets, a testsuite and
    documentation.
    
    Tested on x86_64-*-linux-gnu.
    No visible regressions.
    
    Jose E. Marchesi (9):
      Adapt `info probes' to support printing probes of different types.
      Move `compute_probe_arg' and `compile_probe_arg' to probe.c
      New commands `enable probe' and `disable probe'.
      New gdbarch functions: dtrace_parse_probe_argument,
        dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
      New probe type: DTrace USDT probes.
      Support for DTrace USDT probes in x86_64 targets.
      Simple testsuite for DTrace USDT probes.
      Documentation for DTrace USDT probes.
      Announce the DTrace USDT probes support in NEWS.
    
     gdb/ChangeLog                           |  120 ++++
     gdb/Makefile.in                         |    4 +-
     gdb/NEWS                                |    3 +
     gdb/acinclude.m4                        |    3 +
     gdb/amd64-linux-tdep.c                  |  148 +++++
     gdb/breakpoint.c                        |    3 +-
     gdb/configure                           |   26 +-
     gdb/configure.ac                        |   16 +-
     gdb/doc/ChangeLog                       |   13 +
     gdb/doc/gdb.texinfo                     |   85 ++-
     gdb/dtrace-probe.c                      |  909 +++++++++++++++++++++++++++
     gdb/gdbarch.c                           |  128 ++++
     gdb/gdbarch.h                           |   36 ++
     gdb/gdbarch.sh                          |   16 +
     gdb/probe.c                             |  338 +++++++++-
     gdb/probe.h                             |   18 +
     gdb/stap-probe.c                        |  123 +---
     gdb/testsuite/ChangeLog                 |   18 +
     gdb/testsuite/aclocal.m4                |    1 +
     gdb/testsuite/configure                 |   62 ++
     gdb/testsuite/configure.ac              |    9 +
     gdb/testsuite/gdb.base/dtrace-probe.c   |   38 ++
     gdb/testsuite/gdb.base/dtrace-probe.d   |   21 +
     gdb/testsuite/gdb.base/dtrace-probe.exp |  106 ++++
     gdb/testsuite/gdb.base/stap-probe.exp   |    2 +-
     gdb/testsuite/lib/dtrace.exp            |   71 +++
     gdb/testsuite/lib/pdtrace.in            | 1033 +++++++++++++++++++++++++++++++
     27 files changed, 3170 insertions(+), 180 deletions(-)
     create mode 100644 gdb/dtrace-probe.c
     create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
     create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
     create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
     create mode 100644 gdb/testsuite/lib/dtrace.exp
     create mode 100755 gdb/testsuite/lib/pdtrace.in

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

* Re: [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types.
  2015-02-02 10:57 ` [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
@ 2015-02-17  1:12   ` Sergio Durigan Junior
  0 siblings, 0 replies; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:12 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> A "probe type" (backend for the probe abstraction implemented in
> probe.[ch]) can extend the information printed by `info probes' by
> defining additional columns.  This means that when `info probes' is
> used to print all the probes regardless of their types, some of the
> columns will be "not applicable" to some of the probes (like, say, the
> Semaphore column only makes sense for SystemTap probes).  This patch
> makes `info probes' fill these slots with "n/a" marks (currently it
> breaks the table) and not include headers for which no actual probe
> has been found in the list of defined probes.
>
> This patch also adds support for a new generic column "Type", that
> displays the type of each probe.  SystemTap probes identify themselves
> as "stap" probes.

Thanks for the patch.  Just a tiny nit.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* probe.c (print_ui_out_not_applicables): New function.
> 	(exists_probe_with_pops): Likewise.
> 	(info_probes_for_ops): Do not include column headers for probe
> 	types for which no probe has been actually found on any object.
> 	Also invoke `print_ui_out_not_applicables' in order to match the
> 	column rows with the header when probes of several types are
> 	listed.
> 	Print the "Type" column.
> 	* probe.h (probe_ops): Added a new probe operation `type_name'.
> 	* stap-probe.c (stap_probe_ops): Add `stap_type_name'.
> 	(stap_type_name): New function.
> ---
>  gdb/ChangeLog    |   14 ++++++++++
>  gdb/probe.c      |   76 +++++++++++++++++++++++++++++++++++++++++++++++-------
>  gdb/probe.h      |    6 +++++
>  gdb/stap-probe.c |   12 ++++++++-
>  4 files changed, 97 insertions(+), 11 deletions(-)
>
> diff --git a/gdb/probe.c b/gdb/probe.c
> index 56b5fc1..be3e656 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -410,6 +410,31 @@ gen_ui_out_table_header_info (VEC (bound_probe_s) *probes,
>    do_cleanups (c);
>  }
>  
> +/* Helper function to print not-applicable strings for all the extra
> +   columns defined in a probe_ops.  */
> +
> +static void
> +print_ui_out_not_applicables (const struct probe_ops *pops)
> +{
> +  struct cleanup *c;
> +  VEC (info_probe_column_s) *headings = NULL;
> +  info_probe_column_s *column;
> +  int ix;
> +
> +  if (pops->gen_info_probes_table_header == NULL)
> +    return;
> +
> +  c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
> +  pops->gen_info_probes_table_header (&headings);
> +
> +  for (ix = 0;
> +       VEC_iterate (info_probe_column_s, headings, ix, column);
> +       ++ix)
> +    ui_out_field_string (current_uiout, column->field_name, _("n/a"));
> +
> +  do_cleanups (c);
> +}
> +
>  /* Helper function to print extra information about a probe and an objfile
>     represented by PROBE.  */
>  
> @@ -482,6 +507,23 @@ get_number_extra_fields (const struct probe_ops *pops)
>    return n;
>  }
>  
> +/* Helper function that returns 1 if there is a probe in PROBES
> +   featuring the given POPS.  It returns 0 otherwise.  */
> +
> +static int
> +exists_probe_with_pops (VEC (bound_probe_s) *probes,
> +			const struct probe_ops *pops)
> +{
> +  struct bound_probe *probe;
> +  int ix;
> +
> +  for (ix = 0; VEC_iterate (bound_probe_s, probes, ix, probe); ++ix)
> +    if (probe->probe->pops == pops)
> +      return 1;
> +
> +  return 0;
> +}
> +
>  /* See comment in probe.h.  */
>  
>  void
> @@ -497,6 +539,7 @@ info_probes_for_ops (const char *arg, int from_tty,
>    size_t size_name = strlen ("Name");
>    size_t size_objname = strlen ("Object");
>    size_t size_provider = strlen ("Provider");
> +  size_t size_type = strlen ("Type");
>    struct bound_probe *probe;
>    struct gdbarch *gdbarch = get_current_arch ();
>  
> @@ -517,6 +560,9 @@ info_probes_for_ops (const char *arg, int from_tty,
>  	}
>      }
>  
> +  probes = collect_probes (objname, provider, probe_name, pops);
> +  make_cleanup (VEC_cleanup (probe_p), &probes);
> +
>    if (pops == NULL)
>      {
>        const struct probe_ops *po;
> @@ -529,18 +575,18 @@ info_probes_for_ops (const char *arg, int from_tty,
>  
>  	 To do that, we iterate over all probe_ops, querying each one about
>  	 its extra fields, and incrementing `ui_out_extra_fields' to reflect
> -	 that number.  */
> +	 that number.  But note that we ignore the probe_ops for which no probes
> +         are defined with the given search criteria.  */

This comment line is not correctly indented.

>  
>        for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
> -	ui_out_extra_fields += get_number_extra_fields (po);
> +	if (exists_probe_with_pops (probes, po))
> +	  ui_out_extra_fields += get_number_extra_fields (po);
>      }
>    else
>      ui_out_extra_fields = get_number_extra_fields (pops);
>  
> -  probes = collect_probes (objname, provider, probe_name, pops);
> -  make_cleanup (VEC_cleanup (probe_p), &probes);
>    make_cleanup_ui_out_table_begin_end (current_uiout,
> -				       4 + ui_out_extra_fields,
> +				       5 + ui_out_extra_fields,
>  				       VEC_length (bound_probe_s, probes),
>  				       "StaticProbes");
>  
> @@ -552,15 +598,19 @@ info_probes_for_ops (const char *arg, int from_tty,
>    /* What's the size of an address in our architecture?  */
>    size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
>  
> -  /* Determining the maximum size of each field (`provider', `name' and
> -     `objname').  */
> +  /* Determining the maximum size of each field (`type', `provider',
> +     `name' and `objname').  */
>    for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
>      {
> +      const char *probe_type = probe->probe->pops->type_name (probe->probe);
> +
> +      size_type = max (strlen (probe_type), size_type);
>        size_name = max (strlen (probe->probe->name), size_name);
>        size_provider = max (strlen (probe->probe->provider), size_provider);
>        size_objname = max (strlen (objfile_name (probe->objfile)), size_objname);
>      }
>  
> +  ui_out_table_header (current_uiout, size_type, ui_left, "type", _("Type"));
>    ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
>  		       _("Provider"));
>    ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
> @@ -571,10 +621,12 @@ info_probes_for_ops (const char *arg, int from_tty,
>        const struct probe_ops *po;
>        int ix;
>  
> -      /* We have to generate the table header for each new probe type that we
> -	 will print.  */
> +      /* We have to generate the table header for each new probe type
> +	 that we will print.  Note that this excludes probe types not
> +	 having any defined probe with the search criteria.  */
>        for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
> -	gen_ui_out_table_header_info (probes, po);
> +	if (exists_probe_with_pops (probes, po))
> +	  gen_ui_out_table_header_info (probes, po);
>      }
>    else
>      gen_ui_out_table_header_info (probes, pops);
> @@ -586,9 +638,11 @@ info_probes_for_ops (const char *arg, int from_tty,
>    for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
>      {
>        struct cleanup *inner;
> +      const char *probe_type = probe->probe->pops->type_name (probe->probe);
>  
>        inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
>  
> +      ui_out_field_string (current_uiout, "type",probe_type);
>        ui_out_field_string (current_uiout, "provider", probe->probe->provider);
>        ui_out_field_string (current_uiout, "name", probe->probe->name);
>        ui_out_field_core_addr (current_uiout, "addr",
> @@ -604,6 +658,8 @@ info_probes_for_ops (const char *arg, int from_tty,
>  	       ++ix)
>  	    if (probe->probe->pops == po)
>  	      print_ui_out_info (probe->probe);
> +	    else if (exists_probe_with_pops (probes, po))
> +	      print_ui_out_not_applicables (po);
>  	}
>        else
>  	print_ui_out_info (probe->probe);
> diff --git a/gdb/probe.h b/gdb/probe.h
> index 1dd582d..5df1976 100644
> --- a/gdb/probe.h
> +++ b/gdb/probe.h
> @@ -113,6 +113,12 @@ struct probe_ops
>  
>      void (*destroy) (struct probe *probe);
>  
> +    /* Return a pointer to a name identifying the probe type.  This is
> +       the string that will be displayed in the "Type" column of the
> +       `info probes' command.  */
> +
> +    const char *(*type_name) (struct probe *probe);
> +
>      /* Function responsible for providing the extra fields that will be
>         printed in the `info probes' command.  It should fill HEADS
>         with whatever extra fields it needs.  If the backend doesn't need
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index d7d9cf1..e534b6d 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1703,6 +1703,15 @@ stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
>      }
>  }
>  
> +/* Implementation of the type_name method.  */
> +
> +static const char *
> +stap_type_name (struct probe *probe)
> +{
> +  gdb_assert (probe->pops == &stap_probe_ops);
> +  return "stap";
> +}
> +
>  static int
>  stap_probe_is_linespec (const char **linespecp)
>  {
> @@ -1743,7 +1752,7 @@ stap_gen_info_probes_table_values (struct probe *probe_generic,
>  /* SystemTap probe_ops.  */
>  
>  static const struct probe_ops stap_probe_ops =
> -{
> +  {
>    stap_probe_is_linespec,
>    stap_get_probes,
>    stap_get_probe_address,
> @@ -1754,6 +1763,7 @@ static const struct probe_ops stap_probe_ops =
>    stap_set_semaphore,
>    stap_clear_semaphore,
>    stap_probe_destroy,
> +  stap_type_name,
>    stap_gen_info_probes_table_header,
>    stap_gen_info_probes_table_values,
>  };
> -- 
> 1.7.10.4

I see you fixed everything I mentioned before, so I have no further
comments.  This is OK with the modifications requested.

Thank you for doing this.

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c
  2015-02-02 10:57 ` [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
@ 2015-02-17  1:13   ` Sergio Durigan Junior
  0 siblings, 0 replies; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:13 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch moves the `compute_probe_arg' and `compile_probe_arg' functions
> from stap-probe.c to probe.c.  The rationale is that it is reasonable to
> assume that all backends will provide the `$_probe_argN' convenience
> variables, and that the user must be placed on the PC of the probe when
> requesting that information.  The value and type of the argument can still be
> determined by the probe backend via the `pops->evaluate_probe_argument' and
> `pops->compile_to_ax' handlers.
>
> Note that a test in gdb.base/stap-probe.exp had to be adjusted because the "No
> SystemTap probe at PC" messages are now "No probe at PC".

Thanks for the patch.  It was already approved before, and I have no
further comments about it.  OK.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* probe.c (compute_probe_arg): Moved from stap-probe.c
> 	(compile_probe_arg): Likewise.
> 	(probe_funcs): Likewise.
> 	* stap-probe.c (compute_probe_arg): Moved to probe.c.
> 	(compile_probe_arg): Likewise.
> 	(probe_funcs): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* gdb.base/stap-probe.exp (stap_test): Remove "SystemTap" from
> 	expected message when trying to access $_probe_* convenience
> 	variables while not on a probe.
> ---
>  gdb/ChangeLog                         |    9 +++
>  gdb/probe.c                           |  111 +++++++++++++++++++++++++++++++++
>  gdb/stap-probe.c                      |  109 --------------------------------
>  gdb/testsuite/ChangeLog               |    6 ++
>  gdb/testsuite/gdb.base/stap-probe.exp |    2 +-
>  5 files changed, 127 insertions(+), 110 deletions(-)
>
> diff --git a/gdb/probe.c b/gdb/probe.c
> index be3e656..98113eb 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -30,6 +30,9 @@
>  #include "gdb_regex.h"
>  #include "frame.h"
>  #include "arch-utils.h"
> +#include "value.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
>  #include <ctype.h>
>  
>  typedef struct bound_probe bound_probe_s;
> @@ -826,6 +829,87 @@ will show information about all types of probes."),
>    return &info_probes_cmdlist;
>  }
>  
> +\f
> +
> +/* This is called to compute the value of one of the $_probe_arg*
> +   convenience variables.  */
> +
> +static struct value *
> +compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
> +		   void *data)
> +{
> +  struct frame_info *frame = get_selected_frame (_("No frame selected"));
> +  CORE_ADDR pc = get_frame_pc (frame);
> +  int sel = (int) (uintptr_t) data;
> +  struct bound_probe pc_probe;
> +  const struct sym_probe_fns *pc_probe_fns;
> +  unsigned n_args;
> +
> +  /* SEL == -1 means "_probe_argc".  */
> +  gdb_assert (sel >= -1);
> +
> +  pc_probe = find_probe_by_pc (pc);
> +  if (pc_probe.probe == NULL)
> +    error (_("No probe at PC %s"), core_addr_to_string (pc));
> +
> +  n_args = get_probe_argument_count (pc_probe.probe, frame);
> +  if (sel == -1)
> +    return value_from_longest (builtin_type (arch)->builtin_int, n_args);
> +
> +  if (sel >= n_args)
> +    error (_("Invalid probe argument %d -- probe has %u arguments available"),
> +	   sel, n_args);
> +
> +  return evaluate_probe_argument (pc_probe.probe, sel, frame);
> +}
> +
> +/* This is called to compile one of the $_probe_arg* convenience
> +   variables into an agent expression.  */
> +
> +static void
> +compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
> +		   struct axs_value *value, void *data)
> +{
> +  CORE_ADDR pc = expr->scope;
> +  int sel = (int) (uintptr_t) data;
> +  struct bound_probe pc_probe;
> +  const struct sym_probe_fns *pc_probe_fns;
> +  int n_args;
> +  struct frame_info *frame = get_selected_frame (NULL);
> +
> +  /* SEL == -1 means "_probe_argc".  */
> +  gdb_assert (sel >= -1);
> +
> +  pc_probe = find_probe_by_pc (pc);
> +  if (pc_probe.probe == NULL)
> +    error (_("No probe at PC %s"), core_addr_to_string (pc));
> +
> +  n_args = get_probe_argument_count (pc_probe.probe, frame);
> +
> +  if (sel == -1)
> +    {
> +      value->kind = axs_rvalue;
> +      value->type = builtin_type (expr->gdbarch)->builtin_int;
> +      ax_const_l (expr, n_args);
> +      return;
> +    }
> +
> +  gdb_assert (sel >= 0);
> +  if (sel >= n_args)
> +    error (_("Invalid probe argument %d -- probe has %d arguments available"),
> +	   sel, n_args);
> +
> +  pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
> +}
> +
> +static const struct internalvar_funcs probe_funcs =
> +{
> +  compute_probe_arg,
> +  compile_probe_arg,
> +  NULL
> +};
> +
> +
>  VEC (probe_ops_cp) *all_probe_ops;
>  
>  void _initialize_probe (void);
> @@ -835,6 +919,33 @@ _initialize_probe (void)
>  {
>    VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
>  
> +  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
> +				(void *) (uintptr_t) -1);
> +  create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
> +				(void *) (uintptr_t) 0);
> +  create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
> +				(void *) (uintptr_t) 1);
> +  create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
> +				(void *) (uintptr_t) 2);
> +  create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
> +				(void *) (uintptr_t) 3);
> +  create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
> +				(void *) (uintptr_t) 4);
> +  create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
> +				(void *) (uintptr_t) 5);
> +  create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
> +				(void *) (uintptr_t) 6);
> +  create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
> +				(void *) (uintptr_t) 7);
> +  create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
> +				(void *) (uintptr_t) 8);
> +  create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
> +				(void *) (uintptr_t) 9);
> +  create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
> +				(void *) (uintptr_t) 10);
> +  create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
> +				(void *) (uintptr_t) 11);
> +
>    add_cmd ("all", class_info, info_probes_command,
>  	   _("\
>  Show information about all type of probes."),
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index e534b6d..e898f7e 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1365,79 +1365,6 @@ stap_probe_destroy (struct probe *probe_generic)
>  
>  \f
>  
> -/* This is called to compute the value of one of the $_probe_arg*
> -   convenience variables.  */
> -
> -static struct value *
> -compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
> -		   void *data)
> -{
> -  struct frame_info *frame = get_selected_frame (_("No frame selected"));
> -  CORE_ADDR pc = get_frame_pc (frame);
> -  int sel = (int) (uintptr_t) data;
> -  struct bound_probe pc_probe;
> -  const struct sym_probe_fns *pc_probe_fns;
> -  unsigned n_args;
> -
> -  /* SEL == -1 means "_probe_argc".  */
> -  gdb_assert (sel >= -1);
> -
> -  pc_probe = find_probe_by_pc (pc);
> -  if (pc_probe.probe == NULL)
> -    error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> -
> -  n_args = get_probe_argument_count (pc_probe.probe, frame);
> -  if (sel == -1)
> -    return value_from_longest (builtin_type (arch)->builtin_int, n_args);
> -
> -  if (sel >= n_args)
> -    error (_("Invalid probe argument %d -- probe has %u arguments available"),
> -	   sel, n_args);
> -
> -  return evaluate_probe_argument (pc_probe.probe, sel, frame);
> -}
> -
> -/* This is called to compile one of the $_probe_arg* convenience
> -   variables into an agent expression.  */
> -
> -static void
> -compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
> -		   struct axs_value *value, void *data)
> -{
> -  CORE_ADDR pc = expr->scope;
> -  int sel = (int) (uintptr_t) data;
> -  struct bound_probe pc_probe;
> -  const struct sym_probe_fns *pc_probe_fns;
> -  int n_args;
> -  struct frame_info *frame = get_selected_frame (NULL);
> -
> -  /* SEL == -1 means "_probe_argc".  */
> -  gdb_assert (sel >= -1);
> -
> -  pc_probe = find_probe_by_pc (pc);
> -  if (pc_probe.probe == NULL)
> -    error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> -
> -  n_args = get_probe_argument_count (pc_probe.probe, frame);
> -
> -  if (sel == -1)
> -    {
> -      value->kind = axs_rvalue;
> -      value->type = builtin_type (expr->gdbarch)->builtin_int;
> -      ax_const_l (expr, n_args);
> -      return;
> -    }
> -
> -  gdb_assert (sel >= 0);
> -  if (sel >= n_args)
> -    error (_("Invalid probe argument %d -- probe has %d arguments available"),
> -	   sel, n_args);
> -
> -  pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
> -}
> -
> -\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'
> @@ -1514,15 +1441,6 @@ stap_clear_semaphore (struct probe *probe_generic, struct objfile *objfile,
>    stap_modify_semaphore (addr, 0, gdbarch);
>  }
>  
> -/* Implementation of `$_probe_arg*' set of variables.  */
> -
> -static const struct internalvar_funcs probe_funcs =
> -{
> -  compute_probe_arg,
> -  compile_probe_arg,
> -  NULL
> -};
> -
>  /* Helper function that parses the information contained in a
>     SystemTap's probe.  Basically, the information consists in:
>  
> @@ -1793,33 +1711,6 @@ _initialize_stap_probe (void)
>  			     show_stapexpressiondebug,
>  			     &setdebuglist, &showdebuglist);
>  
> -  create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
> -				(void *) (uintptr_t) -1);
> -  create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
> -				(void *) (uintptr_t) 0);
> -  create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
> -				(void *) (uintptr_t) 1);
> -  create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
> -				(void *) (uintptr_t) 2);
> -  create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
> -				(void *) (uintptr_t) 3);
> -  create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
> -				(void *) (uintptr_t) 4);
> -  create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
> -				(void *) (uintptr_t) 5);
> -  create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
> -				(void *) (uintptr_t) 6);
> -  create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
> -				(void *) (uintptr_t) 7);
> -  create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
> -				(void *) (uintptr_t) 8);
> -  create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
> -				(void *) (uintptr_t) 9);
> -  create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
> -				(void *) (uintptr_t) 10);
> -  create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
> -				(void *) (uintptr_t) 11);
> -
>    add_cmd ("stap", class_info, info_probes_stap_command,
>  	   _("\
>  Show information about SystemTap static probes.\n\
> diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
> index 73e6ca3..7310b25 100644
> --- a/gdb/testsuite/gdb.base/stap-probe.exp
> +++ b/gdb/testsuite/gdb.base/stap-probe.exp
> @@ -30,7 +30,7 @@ proc stap_test {exec_name {arg ""}} {
>  	return -1
>      }
>  
> -    gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
> +    gdb_test "print \$_probe_argc" "No probe at PC $hex" \
>  	"check argument not at probe point"
>  
>      gdb_test "info probes stap" \
> -- 
> 1.7.10.4

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
  2015-02-02 10:57 ` [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
@ 2015-02-17  1:14   ` Sergio Durigan Junior
  0 siblings, 0 replies; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:14 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch adds several gdbarch functions (along with the corresponding
> predicates): `dtrace_parse_probe_argument', `dtrace_probe_is_enabled',
> `dtrace_enable_probe' and `dtrace_disable_probe'.  These functions will
> be implemented by target-specific code, and called from the DTrace
> probes implementation in order to calculate the value of probe
> arguments, and manipulate is-enabled probes.

This was already approved.  OK.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* gdbarch.sh (dtrace_parse_probe_argument): New.
> 	(dtrace_probe_is_enabled): Likewise.
> 	(dtrace_enable_probe): Likewise.
> 	(dtrace_disable_probe): Likewise.
> 	* gdbarch.c: Regenerate.
> 	* gdbarch.h: Regenerate.
> ---
>  gdb/ChangeLog  |    9 ++++
>  gdb/gdbarch.c  |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/gdbarch.h  |   36 ++++++++++++++++
>  gdb/gdbarch.sh |   16 +++++++
>  4 files changed, 189 insertions(+)
>
> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
> index b35da35..aa1a369 100644
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -303,6 +303,10 @@ struct gdbarch
>    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;
> +  gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument;
> +  gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled;
> +  gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe;
> +  gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe;
>    int has_global_solist;
>    int has_global_breakpoints;
>    gdbarch_has_shared_address_space_ftype *has_shared_address_space;
> @@ -632,6 +636,10 @@ verify_gdbarch (struct gdbarch *gdbarch)
>    /* 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 dtrace_parse_probe_argument, has predicate.  */
> +  /* Skip verify of dtrace_probe_is_enabled, has predicate.  */
> +  /* Skip verify of dtrace_enable_probe, has predicate.  */
> +  /* Skip verify of dtrace_disable_probe, 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 */
> @@ -847,6 +855,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
>                        "gdbarch_dump: double_format = %s\n",
>                        pformat (gdbarch->double_format));
>    fprintf_unfiltered (file,
> +                      "gdbarch_dump: gdbarch_dtrace_disable_probe_p() = %d\n",
> +                      gdbarch_dtrace_disable_probe_p (gdbarch));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: dtrace_disable_probe = <%s>\n",
> +                      host_address_to_string (gdbarch->dtrace_disable_probe));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: gdbarch_dtrace_enable_probe_p() = %d\n",
> +                      gdbarch_dtrace_enable_probe_p (gdbarch));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: dtrace_enable_probe = <%s>\n",
> +                      host_address_to_string (gdbarch->dtrace_enable_probe));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: gdbarch_dtrace_parse_probe_argument_p() = %d\n",
> +                      gdbarch_dtrace_parse_probe_argument_p (gdbarch));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: dtrace_parse_probe_argument = <%s>\n",
> +                      host_address_to_string (gdbarch->dtrace_parse_probe_argument));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: gdbarch_dtrace_probe_is_enabled_p() = %d\n",
> +                      gdbarch_dtrace_probe_is_enabled_p (gdbarch));
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: dtrace_probe_is_enabled = <%s>\n",
> +                      host_address_to_string (gdbarch->dtrace_probe_is_enabled));
> +  fprintf_unfiltered (file,
>                        "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
>                        gdbarch_dummy_id_p (gdbarch));
>    fprintf_unfiltered (file,
> @@ -4203,6 +4235,102 @@ set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
>  }
>  
>  int
> +gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  return gdbarch->dtrace_parse_probe_argument != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->dtrace_parse_probe_argument != NULL);
> +  if (gdbarch_debug >= 2)
> +    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_parse_probe_argument called\n");
> +  gdbarch->dtrace_parse_probe_argument (gdbarch, pstate, narg);
> +}
> +
> +void
> +set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
> +                                         gdbarch_dtrace_parse_probe_argument_ftype dtrace_parse_probe_argument)
> +{
> +  gdbarch->dtrace_parse_probe_argument = dtrace_parse_probe_argument;
> +}
> +
> +int
> +gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  return gdbarch->dtrace_probe_is_enabled != NULL;
> +}
> +
> +int
> +gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->dtrace_probe_is_enabled != NULL);
> +  if (gdbarch_debug >= 2)
> +    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_probe_is_enabled called\n");
> +  return gdbarch->dtrace_probe_is_enabled (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch,
> +                                     gdbarch_dtrace_probe_is_enabled_ftype dtrace_probe_is_enabled)
> +{
> +  gdbarch->dtrace_probe_is_enabled = dtrace_probe_is_enabled;
> +}
> +
> +int
> +gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  return gdbarch->dtrace_enable_probe != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->dtrace_enable_probe != NULL);
> +  if (gdbarch_debug >= 2)
> +    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_enable_probe called\n");
> +  gdbarch->dtrace_enable_probe (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch,
> +                                 gdbarch_dtrace_enable_probe_ftype dtrace_enable_probe)
> +{
> +  gdbarch->dtrace_enable_probe = dtrace_enable_probe;
> +}
> +
> +int
> +gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  return gdbarch->dtrace_disable_probe != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  gdb_assert (gdbarch != NULL);
> +  gdb_assert (gdbarch->dtrace_disable_probe != NULL);
> +  if (gdbarch_debug >= 2)
> +    fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_disable_probe called\n");
> +  gdbarch->dtrace_disable_probe (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch,
> +                                  gdbarch_dtrace_disable_probe_ftype dtrace_disable_probe)
> +{
> +  gdbarch->dtrace_disable_probe = dtrace_disable_probe;
> +}
> +
> +int
>  gdbarch_has_global_solist (struct gdbarch *gdbarch)
>  {
>    gdb_assert (gdbarch != NULL);
> diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
> index b266530..de773a3 100644
> --- a/gdb/gdbarch.h
> +++ b/gdb/gdbarch.h
> @@ -59,6 +59,7 @@ struct syscall;
>  struct agent_expr;
>  struct axs_value;
>  struct stap_parse_info;
> +struct parser_state;
>  struct ravenscar_arch_ops;
>  struct elf_internal_linux_prpsinfo;
>  struct mem_range;
> @@ -1241,6 +1242,41 @@ typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, s
>  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);
>  
> +/* DTrace related functions.
> +   The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
> +   NARG must be >= 0. */
> +
> +extern int gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
> +extern void gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
> +extern void set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument);
> +
> +/* True if the given ADDR does not contain the instruction sequence
> +   corresponding to a disabled DTrace is-enabled probe. */
> +
> +extern int gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch);
> +
> +typedef int (gdbarch_dtrace_probe_is_enabled_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern int gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled);
> +
> +/* Enable a DTrace is-enabled probe at ADDR. */
> +
> +extern int gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_enable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe);
> +
> +/* Disable a DTrace is-enabled probe at ADDR. */
> +
> +extern int gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_disable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe);
> +
>  /* 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 e12b8b0..fcca995 100755
> --- a/gdb/gdbarch.sh
> +++ b/gdb/gdbarch.sh
> @@ -985,6 +985,21 @@ M:int:stap_is_single_operand:const char *s:s
>  # parser), and should advance the buffer pointer (p->arg).
>  M:int:stap_parse_special_token:struct stap_parse_info *p:p
>  
> +# DTrace related functions.
> +
> +# The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
> +# NARG must be >= 0.
> +M:void:dtrace_parse_probe_argument:struct parser_state *pstate, int narg:pstate, narg
> +
> +# True if the given ADDR does not contain the instruction sequence
> +# corresponding to a disabled DTrace is-enabled probe.
> +M:int:dtrace_probe_is_enabled:CORE_ADDR addr:addr
> +
> +# Enable a DTrace is-enabled probe at ADDR.
> +M:void:dtrace_enable_probe:CORE_ADDR addr:addr
> +
> +# Disable a DTrace is-enabled probe at ADDR.
> +M:void:dtrace_disable_probe:CORE_ADDR addr:addr
>  
>  # True if the list of shared libraries is one and only for all
>  # processes, as opposed to a list of shared libraries per inferior.
> @@ -1213,6 +1228,7 @@ struct syscall;
>  struct agent_expr;
>  struct axs_value;
>  struct stap_parse_info;
> +struct parser_state;
>  struct ravenscar_arch_ops;
>  struct elf_internal_linux_prpsinfo;
>  struct mem_range;
> -- 
> 1.7.10.4

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-02-02 10:57 ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
@ 2015-02-17  1:35   ` Sergio Durigan Junior
  2015-03-25 19:14     ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:35 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch adds a new type of probe to GDB: the DTrace USDT probes.  The new
> type is added by providing functions implementing all the entries of the
> `probe_ops' structure defined in `probe.h'.  The implementation is
> self-contained and does not depend on DTrace source code in any way.

Thanks for the patch.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* breakpoint.c (BREAK_ARGS_HELP): help string updated to mention

Capital letter "H" in "Help string...".

> 	the -probe-dtrace new vpossible value for PROBE_MODIFIER.
> 	* configure.ac (CONFIG_OBS): dtrace-probe.o added if BFD can
> 	handle ELF files.
> 	* Makefile.in (SFILES): dtrace-probe.c added.
> 	* configure: Regenerate.
> 	* dtrace-probe.c: New file.
> 	(SHT_SUNW_dof): New constant.
> 	(dtrace_probe_type): New enum.
> 	(dtrace_probe_arg): New struct.
> 	(dtrace_probe_arg_s): New typedef.
> 	(struct dtrace_probe_enabler): New struct.
> 	(dtrace_probe_enabler_s): New typedef.
> 	(dtrace_probe): New struct.
> 	(dtrace_probe_is_linespec): New function.
> 	(dtrace_dof_sect_type): New enum.
> 	(dtrace_dof_dofh_ident): Likewise.
> 	(dtrace_dof_encoding): Likewise.
> 	(DTRACE_DOF_ENCODE_LSB): Likewise.
> 	(DTRACE_DOF_ENCODE_MSB): Likewise.
> 	(dtrace_dof_hdr): New struct.
> 	(dtrace_dof_sect): Likewise.
> 	(dtrace_dof_provider): Likewise.
> 	(dtrace_dof_probe): Likewise.
> 	(DOF_UINT): New macro.
> 	(DTRACE_DOF_PTR): Likewise.
> 	(DTRACE_DOF_SECT): Likewise.
> 	(dtrace_process_dof_probe): New function.
> 	(dtrace_process_dof): Likewise.
> 	(dtrace_build_arg_exprs): Likewise.
> 	(dtrace_get_arg): Likewise.
> 	(dtrace_get_probes): Likewise.
> 	(dtrace_get_probe_argument_count): Likewise.
> 	(dtrace_can_evaluate_probe_arguments): Likewise.
> 	(dtrace_evaluate_probe_argument): Likewise.
> 	(dtrace_compile_to_ax): Likewise.
> 	(dtrace_probe_destroy): Likewise.
> 	(dtrace_gen_info_probes_table_header): Likewise.
> 	(dtrace_gen_info_probes_table_values): Likewise.
> 	(dtrace_probe_is_enabled): Likewise.
> 	(dtrace_probe_ops): New variable.
> 	(info_probes_dtrace_command): New function.
> 	(_initialize_dtrace_probe): Likewise.
> 	(dtrace_type_name): Likewise.
> ---
>  gdb/ChangeLog      |   47 +++
>  gdb/Makefile.in    |    3 +-
>  gdb/breakpoint.c   |    3 +-
>  gdb/configure      |    2 +-
>  gdb/configure.ac   |    2 +-
>  gdb/dtrace-probe.c |  909 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 962 insertions(+), 4 deletions(-)
>  create mode 100644 gdb/dtrace-probe.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 8addef4..e933b45 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -820,7 +820,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
>  	cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
>  	d-exp.y d-lang.c d-valprint.c \
>  	cp-name-parser.y \
> -	dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
> +	dbxread.c demangle.c dictionary.c disasm.c doublest.c \
> +	dtrace-probe.c dummy-frame.c \
>  	dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
>  	dwarf2-frame-tailcall.c \
>  	elfread.c environ.c eval.c event-loop.c event-top.c \
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index af0c2cf..48e551c 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -15975,7 +15975,8 @@ all_tracepoints (void)
>  command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
>  PROBE_MODIFIER shall be present if the command is to be placed in a\n\
>  probe point.  Accepted values are `-probe' (for a generic, automatically\n\
> -guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\
> +guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
> +`-probe-dtrace' (for a DTrace probe).\n\
>  LOCATION may be a line number, function name, or \"*\" and an address.\n\
>  If a line number is specified, break at start of code for that line.\n\
>  If a function is specified, break at start of code for that function.\n\
> diff --git a/gdb/configure b/gdb/configure
> index 9632f9a..30a54d2 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -13068,7 +13068,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
>    LDFLAGS=$OLD_LDFLAGS
>    LIBS=$OLD_LIBS
>  if test $gdb_cv_var_elf = yes; then
> -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
> +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
>  
>  $as_echo "#define HAVE_ELF 1" >>confdefs.h
>  
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index dfc6947..39fcef2 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -2074,7 +2074,7 @@ AC_SUBST(WIN32LIBS)
>  GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
>                   [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
>  if test $gdb_cv_var_elf = yes; then
> -  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
> +  CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
>    AC_DEFINE(HAVE_ELF, 1,
>  	    [Define if ELF support should be included.])
>    # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
> diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
> new file mode 100644
> index 0000000..9b4a569
> --- /dev/null
> +++ b/gdb/dtrace-probe.c
> @@ -0,0 +1,909 @@
> +/* DTrace probe support for GDB.
> +
> +   Copyright (C) 2014, 2015 Free Software Foundation, Inc.

We are using the years in the following form now:

  2014-2015

This makes it easier for the update scripts to recognize.

> +
> +   Contributed by Oracle, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "probe.h"
> +#include "vec.h"
> +#include "elf-bfd.h"
> +#include "gdbtypes.h"
> +#include "obstack.h"
> +#include "objfiles.h"
> +#include "complaints.h"
> +#include "value.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
> +#include "language.h"
> +#include "parser-defs.h"
> +#include "inferior.h"
> +
> +/* The type of the ELF sections where we will find the DOF programs
> +   with information about probes.  */
> +
> +#ifndef SHT_SUNW_dof
> +# define SHT_SUNW_dof	0x6ffffff4
> +#endif
> +
> +/* Forward declaration.  */
> +
> +static const struct probe_ops dtrace_probe_ops;
> +
> +/* The following structure represents a single argument for the
> +   probe.  */
> +
> +struct dtrace_probe_arg
> +{
> +  /* The type of the probe argument.  */
> +  struct type *type;
> +
> +  /* A string describing the type.  */
> +  char *type_str;
> +
> +  /* The argument converted to an internal GDB expression.  */
> +  struct expression *expr;
> +};
> +
> +typedef struct dtrace_probe_arg dtrace_probe_arg_s;
> +DEF_VEC_O (dtrace_probe_arg_s);
> +
> +/* The following structure represents an enabler for a probe.  */
> +
> +struct dtrace_probe_enabler
> +{
> +  /* Program counter where the is-enabled probe is installed.  The
> +     contents (nops, whatever...) stored at this address are
> +     architecture dependent.  */
> +  CORE_ADDR address;
> +};
> +
> +typedef struct dtrace_probe_enabler dtrace_probe_enabler_s;
> +DEF_VEC_O (dtrace_probe_enabler_s);
> +
> +/* The following structure represents a dtrace probe.  */
> +
> +struct dtrace_probe
> +{
> +  /* Generic information about the probe.  This must be the first
> +     element of this struct, in order to maintain binary compatibility
> +     with the `struct probe' and be able to fully abstract it.  */
> +  struct probe p;
> +
> +  /* A probe can have zero or more arguments.  */
> +  int probe_argc;
> +  VEC (dtrace_probe_arg_s) *args;
> +
> +  /* A probe can have zero or more "enablers" associated with it.  */
> +  VEC (dtrace_probe_enabler_s) *enablers;
> +
> +  /* Whether the expressions for the arguments have been built.  */
> +  unsigned int args_expr_built : 1;
> +};
> +
> +/* Implementation of the probe_is_linespec method.  */
> +
> +static int
> +dtrace_probe_is_linespec (const char **linespecp)
> +{
> +  static const char *const keywords[] = { "-pdtrace", "-probe-dtrace", NULL };
> +
> +  return probe_is_linespec_by_keyword (linespecp, keywords);
> +}
> +
> +/* DOF programs can contain an arbitrary number of sections of 26
> +   different types.  In order to support DTrace USDT probes we only
> +   need to handle a subset of these section types, fortunately.  These
> +   section types are defined in the following enumeration.
> +
> +   See linux/dtrace/dof_defines.h for a complete list of section types
> +   along with their values.  */
> +
> +enum dtrace_dof_sect_type
> +{
> +  /* Null section.  */
> +  DTRACE_DOF_SECT_TYPE_NONE     = 0,
> +  /* A dof_ecbdesc_t. */
> +  DTRACE_DOF_SECT_TYPE_ECBDESC  = 3,
> +  /* A string table.  */
> +  DTRACE_DOF_SECT_TYPE_STRTAB   = 8,
> +  /* A dof_provider_t  */
> +  DTRACE_DOF_SECT_TYPE_PROVIDER = 15,
> +  /* Array of dof_probe_t  */
> +  DTRACE_DOF_SECT_TYPE_PROBES   = 16,
> +  /* An array of probe arg mappings.  */
> +  DTRACE_DOF_SECT_TYPE_PRARGS   = 17,
> +  /* An array of probe arg offsets.  */
> +  DTRACE_DOF_SECT_TYPE_PROFFS   = 18,
> +  /* An array of probe is-enabled offsets.  */
> +  DTRACE_DOF_SECT_TYPE_PRENOFFS = 26

I don't remember if I said that already, but I don't think aligning the
assignments is a good thing to do.  It makes it cumbersome when you're
trying to find where this enum has been defined, for example.  Please,
remove the extra whitespaces.

> +};
> +
> +/* The following collection of data structures map the structure of
> +   DOF entities.  Again, we only cover the subset of DOF used to
> +   implement USDT probes.
> +
> +   See linux/dtrace/dof.h header for a complete list of data
> +   structures.  */
> +
> +/* Offsets to index the dofh_ident[] array defined below.  */
> +
> +enum dtrace_dof_ident
> +{
> +  /* First byte of the magic number.  */
> +  DTRACE_DOF_ID_MAG0     = 0,
> +  /* Second byte of the magic number.  */
> +  DTRACE_DOF_ID_MAG1     = 1,
> +  /* Third byte of the magic number.  */
> +  DTRACE_DOF_ID_MAG2     = 2,
> +  /* Fourth byte of the magic number.  */
> +  DTRACE_DOF_ID_MAG3     = 3,
> +  /* An enum_dof_encoding value.  */
> +  DTRACE_DOF_ID_ENCODING = 5
> +};
> +
> +/* Possible values for dofh_ident[DOF_ID_ENCODING].  */
> +
> +enum dtrace_dof_encoding
> +{
> +  /* The DOF program is little-endian.  */
> +  DTRACE_DOF_ENCODE_LSB = 1,
> +  /* The DOF program is big-endian.  */
> +  DTRACE_DOF_ENCODE_MSB = 2
> +};
> +
> +/* A DOF header, which describes the contents of a DOF program: number
> +   of sections, size, etc.  */
> +
> +struct dtrace_dof_hdr
> +{
> +  /* Identification bytes (see above). */
> +  uint8_t dofh_ident[16];
> +  /* File attribute flags (if any). */
> +  uint32_t dofh_flags;   
> +  /* Size of file header in bytes. */
> +  uint32_t dofh_hdrsize; 
> +  /* Size of section header in bytes. */
> +  uint32_t dofh_secsize; 
> +  /* Number of section headers. */
> +  uint32_t dofh_secnum;  
> +  /* File offset of section headers. */
> +  uint64_t dofh_secoff;  
> +  /* File size of loadable portion. */
> +  uint64_t dofh_loadsz;  
> +  /* File size of entire DOF file. */
> +  uint64_t dofh_filesz;  
> +  /* Reserved for future use. */
> +  uint64_t dofh_pad;     
> +};
> +
> +/* A DOF section, whose contents depend on its type.  The several
> +   supported section types are described in the enum
> +   dtrace_dof_sect_type above.  */
> +
> +struct dtrace_dof_sect
> +{
> +  /* Section type (see the define above). */
> +  uint32_t dofs_type;
> +  /* Section data memory alignment. */
> +  uint32_t dofs_align; 
> +  /* Section flags (if any). */
> +  uint32_t dofs_flags; 
> +  /* Size of section entry (if table). */
> +  uint32_t dofs_entsize;
> +  /* DOF + offset points to the section data. */
> +  uint64_t dofs_offset;
> +  /* Size of section data in bytes.  */
> +  uint64_t dofs_size;  
> +};
> +
> +/* A DOF provider, which is the provider of a probe.  */
> +
> +struct dtrace_dof_provider
> +{
> +  /* Link to a DTRACE_DOF_SECT_TYPE_STRTAB section. */
> +  uint32_t dofpv_strtab; 
> +  /* Link to a DTRACE_DOF_SECT_TYPE_PROBES section. */
> +  uint32_t dofpv_probes; 
> +  /* Link to a DTRACE_DOF_SECT_TYPE_PRARGS section. */
> +  uint32_t dofpv_prargs; 
> +  /* Link to a DTRACE_DOF_SECT_TYPE_PROFFS section. */
> +  uint32_t dofpv_proffs; 
> +  /* Provider name string. */
> +  uint32_t dofpv_name;   
> +  /* Provider attributes. */
> +  uint32_t dofpv_provattr;
> +  /* Module attributes. */
> +  uint32_t dofpv_modattr; 
> +  /* Function attributes. */
> +  uint32_t dofpv_funcattr;
> +  /* Name attributes. */
> +  uint32_t dofpv_nameattr;
> +  /* Args attributes. */
> +  uint32_t dofpv_argsattr;
> +  /* Link to a DTRACE_DOF_SECT_PRENOFFS section. */
> +  uint32_t dofpv_prenoffs;
> +};
> +
> +/* A set of DOF probes and is-enabled probes sharing a base address
> +   and several attributes.  The particular locations and attributes of
> +   each probe are maintained in arrays in several other DOF sections.
> +   See the comment in dtrace_process_dof_probe for details on how
> +   these attributes are stored.  */
> +
> +struct dtrace_dof_probe
> +{
> +  /* Probe base address or offset. */
> +  uint64_t dofpr_addr;   
> +  /* Probe function string. */
> +  uint32_t dofpr_func;   
> +  /* Probe name string. */
> +  uint32_t dofpr_name;   
> +  /* Native argument type strings. */
> +  uint32_t dofpr_nargv;  
> +  /* Translated argument type strings. */
> +  uint32_t dofpr_xargv;  
> +  /* Index of first argument mapping. */
> +  uint32_t dofpr_argidx; 
> +  /* Index of first offset entry. */
> +  uint32_t dofpr_offidx; 
> +  /* Native argument count. */
> +  uint8_t  dofpr_nargc;  
> +  /* Translated argument count. */
> +  uint8_t  dofpr_xargc;  
> +  /* Number of offset entries for probe. */
> +  uint16_t dofpr_noffs;  
> +  /* Index of first is-enabled offset. */
> +  uint32_t dofpr_enoffidx;
> +  /* Number of is-enabled offsets. */
> +  uint16_t dofpr_nenoffs;
> +  /* Reserved for future use. */
> +  uint16_t dofpr_pad1;   
> +  /* Reserved for future use. */
> +  uint32_t dofpr_pad2;   
> +};
> +
> +/* DOF supports two different encodings: MSB (big-endian) and LSB
> +   (little-endian).  The encoding is itself encoded in the DOF header.
> +   The following function returns an unsigned value in the host
> +   endianness.  */
> +
> +#define DOF_UINT(dof, field)						\
> +  extract_unsigned_integer ((gdb_byte *) &(field),			\
> +			    sizeof ((field)),				\
> +			    (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \
> +			      == DTRACE_DOF_ENCODE_MSB)			\
> +			     ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE))
> +
> +/* The following macro applies a given byte offset to a DOF (a pointer
> +   to a dtrace_dof_hdr structure) and returns the resulting
> +   address.  */
> +
> +#define DTRACE_DOF_PTR(dof, offset) (&((char *) (dof))[(offset)])
> +
> +/* The following macro returns a pointer to the beginning of a given
> +   section in a DOF object.  The section is referred to by its index
> +   in the sections array.  */
> +
> +#define DTRACE_DOF_SECT(dof, idx)					\
> +  ((struct dtrace_dof_sect *)						\
> +   DTRACE_DOF_PTR ((dof),						\
> +		   DOF_UINT ((dof), (dof)->dofh_secoff)			\
> +		   + ((idx) * DOF_UINT ((dof), (dof)->dofh_secsize))))
> +
> +/* Helper function to examine the probe described by the given PROBE
> +   and PROVIDER data structures and add it to the PROBESP vector.
> +   STRTAB, OFFTAB, EOFFTAB and ARGTAB are pointers to tables in the
> +   DOF program containing the attributes for the probe.  */
> +
> +static void
> +dtrace_process_dof_probe (struct objfile *objfile,
> +			  struct gdbarch *gdbarch, VEC (probe_p) **probesp,
> +			  struct dtrace_dof_hdr *dof,
> +			  struct dtrace_dof_probe *probe,
> +			  struct dtrace_dof_provider *provider,
> +			  char *strtab, char *offtab, char *eofftab,
> +			  char *argtab, uint64_t strtab_size)
> +{
> +  int i, j, num_probes, num_enablers;
> +  struct cleanup *cleanup;
> +  VEC (dtrace_probe_enabler_s) *enablers;
> +  char *p;
> +
> +  /* Each probe section can define zero or more probes of two
> +     different types:
> +
> +     - probe->dofpr_noffs regular probes whose program counters are
> +       stored in 32bit words starting at probe->dofpr_addr +
> +       offtab[probe->dofpr_offidx].
> +
> +     - probe->dofpr_nenoffs is-enabled probes whose program counters
> +       are stored in 32bit words starting at probe->dofpr_addr +
> +       eofftab[probe->dofpr_enoffidx].
> +
> +     However is-enabled probes are not probes per-se, but an
> +     optimization hack that is implemented in the kernel in a very
> +     similar way than normal probes.  This is how we support
> +     is-enabled probes on GDB:
> +
> +     - Our probes are always DTrace regular probes.
> +
> +     - Our probes can be associated with zero or more "enablers".  The
> +       list of enablers is built from the is-enabled probes defined in
> +       the Probe section.
> +
> +     - Probes having a non-empty list of enablers can be enabled or
> +       disabled using the `enable probe' and `disable probe' commands
> +       respectively.  The `Enabled' column in the output of `info
> +       probes' will read `yes' if the enablers are activated, `no'
> +       otherwise.
> +
> +     - Probes having an empty list of enablers are always enabled.
> +       The `Enabled' column in the output of `info probes' will
> +       read `always'.
> +
> +     It follows that if there are DTrace is-enabled probes defined for
> +     some provider/name but no DTrace regular probes defined then the
> +     GDB user wont be able to enable/disable these conditionals.  */
> +
> +  num_probes = DOF_UINT (dof, probe->dofpr_noffs);
> +  if (num_probes == 0)
> +    return;
> +
> +  /* Build the list of enablers for the probes defined in this Probe
> +     DOF section.  */
> +  enablers = NULL;
> +  cleanup
> +    = make_cleanup (VEC_cleanup (dtrace_probe_enabler_s), &enablers);
> +  num_enablers = DOF_UINT (dof, probe->dofpr_nenoffs);
> +  for (i = 0; i < num_enablers; i++)
> +    {
> +      struct dtrace_probe_enabler enabler;
> +      uint32_t enabler_offset
> +	= ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
> +
> +      enabler.address = DOF_UINT (dof, probe->dofpr_addr)
> +	+ DOF_UINT (dof, enabler_offset);
> +      VEC_safe_push (dtrace_probe_enabler_s, enablers, &enabler);
> +    }
> +
> +  for (i = 0; i < num_probes; i++)
> +    {
> +      uint32_t probe_offset
> +	= ((uint32_t *) offtab)[DOF_UINT (dof, probe->dofpr_offidx) + i];
> +      struct dtrace_probe *ret
> +	= obstack_alloc (&objfile->per_bfd->storage_obstack, sizeof (*ret));
> +
> +      ret->p.pops = &dtrace_probe_ops;
> +      ret->p.arch = gdbarch;
> +      ret->args_expr_built = 0;
> +
> +      /* Set the provider and the name of the probe.  */
> +      ret->p.provider
> +	= xstrdup (strtab + DOF_UINT (dof, provider->dofpv_name));
> +      ret->p.name = xstrdup (strtab + DOF_UINT (dof, probe->dofpr_name));
> +
> +      /* The probe address.  */
> +      ret->p.address
> +	= DOF_UINT (dof, probe->dofpr_addr) + DOF_UINT (dof, probe_offset);
> +
> +      /* Number of arguments in the probe.  */
> +      ret->probe_argc = DOF_UINT (dof, probe->dofpr_nargc);
> +
> +      /* Store argument type descriptions.  A description of the type
> +         of the argument is in the (J+1)th null-terminated string
> +         starting at 'strtab' + 'probe->dofpr_nargv'.  */
> +      ret->args = NULL;
> +      p = strtab + DOF_UINT (dof, probe->dofpr_nargv);
> +      for (j = 0; j < ret->probe_argc; j++)
> +	{
> +	  struct dtrace_probe_arg arg;
> +	  struct expression *expr;
> +
> +	  arg.type_str = xstrdup (p);
> +
> +	  /* Use strtab_size as a sentinel.  */
> +	  while (*p++ != '\0' && p - strtab < strtab_size);
> +
> +	  /* Try to parse a type expression from the type string.  If
> +	     this does not work then we set the type to `long
> +	     int'.  */
> +          arg.type = builtin_type (gdbarch)->builtin_long;
> +	  expr = parse_expression (arg.type_str);
> +	  if (expr->elts[0].opcode == OP_TYPE)
> +	    arg.type = expr->elts[1].type;
> +
> +	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
> +	}
> +
> +      /* Add the vector of enablers to this probe, if any.  */
> +      ret->enablers = VEC_copy (dtrace_probe_enabler_s, enablers);
> +
> +      /* Successfully created probe.  */
> +      VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
> +    }
> +
> +  do_cleanups (cleanup);
> +}
> +
> +/* Helper function to collect the probes described in the DOF program
> +   whose header is pointed by DOF and add them to the PROBESP vector.
> +   SECT is the ELF section containing the DOF program and OBJFILE is
> +   its containing object file.  */
> +
> +static void
> +dtrace_process_dof (asection *sect, struct objfile *objfile,
> +		    VEC (probe_p) **probesp, struct dtrace_dof_hdr *dof)
> +{
> +  bfd *abfd = objfile->obfd;
> +  int size = bfd_get_arch_size (abfd) / 8;
> +  struct gdbarch *gdbarch = get_objfile_arch (objfile);
> +  struct dtrace_dof_sect *section;
> +  int i;
> +
> +  /* The first step is to check for the DOF magic number.  If no valid
> +     DOF data is found in the section then a complaint is issued to
> +     the user and the section skipped.  */
> +  if (dof->dofh_ident[DTRACE_DOF_ID_MAG0] != 0x7F
> +      || dof->dofh_ident[DTRACE_DOF_ID_MAG1] != 'D'
> +      || dof->dofh_ident[DTRACE_DOF_ID_MAG2] != 'O'
> +      || dof->dofh_ident[DTRACE_DOF_ID_MAG3] != 'F')
> +    goto invalid_dof_data;
> +
> +  /* Make sure the encoding mark is either DTRACE_DOF_ENCODE_LSB or
> +     DTRACE_DOF_ENCODE_MSB.  */
> +  if (dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_LSB
> +      && dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_MSB)
> +    goto invalid_dof_data;
> +
> +  /* Make sure this DOF is not an enabling DOF, i.e. there are no ECB
> +     Description sections.  */
> +  section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
> +						       DOF_UINT (dof, dof->dofh_secoff));
> +  for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
> +    if (section->dofs_type == DTRACE_DOF_SECT_TYPE_ECBDESC)
> +      return;
> +
> +  /* Iterate over any section of type Provider and extract the probe
> +     information from them.  If there are no "provider" sections on
> +     the DOF then we just return.  */
> +  section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
> +						       DOF_UINT (dof, dof->dofh_secoff));
> +  for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
> +    if (DOF_UINT (dof, section->dofs_type) == DTRACE_DOF_SECT_TYPE_PROVIDER)
> +      {
> +	struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
> +	  DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
> +	struct dtrace_dof_sect *strtab_s
> +	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_strtab));
> +	struct dtrace_dof_sect *probes_s
> +	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_probes));
> +	struct dtrace_dof_sect *args_s
> +	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prargs));
> +	struct dtrace_dof_sect *offsets_s
> +	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_proffs));
> +	struct dtrace_dof_sect *eoffsets_s
> +	  = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prenoffs));
> +	char *strtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, strtab_s->dofs_offset));
> +	char *offtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, offsets_s->dofs_offset));
> +	char *eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
> +	char *argtab  = DTRACE_DOF_PTR (dof, DOF_UINT (dof, args_s->dofs_offset));
> +	unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
> +	int num_probes;
> +
> +	/* Very, unlikely, but could crash gdb if not handled
> +	   properly.  */
> +	if (entsize == 0)
> +	  goto invalid_dof_data;
> +
> +	num_probes = DOF_UINT (dof, probes_s->dofs_size) / entsize;
> +
> +	for (i = 0; i < num_probes; i++)
> +	  {
> +	    struct dtrace_dof_probe *probe = (struct dtrace_dof_probe *)
> +	      DTRACE_DOF_PTR (dof, DOF_UINT (dof, probes_s->dofs_offset)
> +			      + (i * DOF_UINT (dof, probes_s->dofs_entsize)));
> +
> +	    dtrace_process_dof_probe (objfile,
> +				      gdbarch, probesp,
> +				      dof, probe,
> +				      provider, strtab, offtab, eofftab, argtab,
> +				      DOF_UINT (dof, strtab_s->dofs_size));
> +	  }
> +      }
> +
> +  return;
> +	  
> + invalid_dof_data:
> +  complaint (&symfile_complaints,
> +	     _("skipping section '%s' which does not contain valid DOF data."),
> +	     sect->name);
> +}
> +
> +/* Helper function to build the GDB internal expressiosn that, once
> +   evaluated, will calculate the values of the arguments of a given
> +   PROBE.  */
> +
> +static void
> +dtrace_build_arg_exprs (struct dtrace_probe *probe,
> +			struct gdbarch *gdbarch)
> +{
> +  struct parser_state pstate;
> +  struct dtrace_probe_arg *arg;
> +  int i;
> +
> +  probe->args_expr_built = 1;
> +
> +  /* Iterate over the arguments in the probe and build the
> +     corresponding GDB internal expression that will generate the
> +     value of the argument when executed at the PC of the probe.  */
> +  for (i = 0; i < probe->probe_argc; i++)
> +    {
> +      struct cleanup *back_to;
> +
> +      arg = VEC_index (dtrace_probe_arg_s, probe->args, i);
> +
> +      /* Initialize the expression buffer in the parser state.  The
> +	 language does not matter, since we are using our own
> +	 parser.  */
> +      initialize_expout (&pstate, 10, current_language, gdbarch);
> +      back_to = make_cleanup (free_current_contents, &pstate.expout);
> +
> +      /* The argument value, which is ABI dependent and casted to
> +	 `long int'.  */
> +      gdbarch_dtrace_parse_probe_argument (gdbarch, &pstate, i);
> +
> +      discard_cleanups (back_to);
> +
> +      /* Casting to the expected type, but only if the type was
> +	 recognized at probe load time.  Otherwise the argument will
> +	 be evaluated as the long integer passed to the probe.  */
> +      if (arg->type != NULL)
> +	{
> +	  write_exp_elt_opcode (&pstate, UNOP_CAST);
> +	  write_exp_elt_type   (&pstate, arg->type);

Don't align open parentheses.

> +	  write_exp_elt_opcode (&pstate, UNOP_CAST);
> +	}     

Extraneous whitespaces after '}'.

> +
> +      reallocate_expout (&pstate);
> +      arg->expr = pstate.expout;
> +      prefixify_expression (arg->expr);
> +    }
> +}
> +
> +/* Helper function to return the Nth argument of a given PROBE.  */
> +
> +static struct dtrace_probe_arg *
> +dtrace_get_arg (struct dtrace_probe *probe, unsigned n,
> +		struct gdbarch *gdbarch)
> +{
> +  if (!probe->args_expr_built)
> +    dtrace_build_arg_exprs (probe, gdbarch);
> +
> +  return VEC_index (dtrace_probe_arg_s, probe->args, n);
> +}
> +
> +/* Implementation of the get_probes method.  */
> +
> +static void
> +dtrace_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
> +{
> +  bfd *abfd = objfile->obfd;
> +  asection *sect = NULL;
> +
> +  /* Do nothing in case this is a .debug file, instead of the objfile
> +     itself.  */
> +  if (objfile->separate_debug_objfile_backlink != NULL)
> +    return;
> +
> +  /* Iterate over the sections in OBJFILE looking for DTrace
> +     information.  */
> +  for (sect = abfd->sections; sect != NULL; sect = sect->next)
> +    {
> +      if (elf_section_data (sect)->this_hdr.sh_type == SHT_SUNW_dof)
> +	{
> +	  struct dtrace_dof_hdr *dof;
> +
> +	  /* Read the contents of the DOF section and then process it to
> +	     extract the information of any probe defined into it.  */
> +	  if (!bfd_malloc_and_get_section (abfd, sect, (bfd_byte **) &dof))
> +	    complaint (&symfile_complaints,
> +		       _("could not obtain the contents of"
> +			 "section '%s' in objfile `%s'."),
> +		       sect->name, abfd->filename);
> +      

Extraneous whitespaces in the line above.

> +	  dtrace_process_dof (sect, objfile, probesp, dof);
> +	  xfree (dof);
> +	}
> +    }
> +}
> +
> +/* Helper function to determine whether a given probe is "enabled" or
> +   "disabled".  A disabled probe is a probe in which one or more
> +   enablers are disabled.  */
> +
> +static int
> +dtrace_probe_is_enabled (struct dtrace_probe *probe)
> +{
> +  int i;
> +  struct gdbarch *gdbarch = probe->p.arch;
> +  struct dtrace_probe_enabler *enabler;
> +
> +  for (i = 0;
> +       VEC_iterate (dtrace_probe_enabler_s, probe->enablers, i, enabler);
> +       i++)
> +    if (!gdbarch_dtrace_probe_is_enabled (gdbarch, enabler->address))
> +      return 0;
> +
> +  return 1;
> +}
> +
> +/* Implementation of the get_probe_address method.  */
> +
> +static CORE_ADDR
> +dtrace_get_probe_address (struct probe *probe, struct objfile *objfile)
> +{
> +  gdb_assert (probe->pops == &dtrace_probe_ops);
> +  return probe->address + ANOFFSET (objfile->section_offsets,
> +				    SECT_OFF_DATA (objfile));
> +}
> +
> +/* Implementation of the get_probe_argument_count method.  */
> +
> +static unsigned
> +dtrace_get_probe_argument_count (struct probe *probe_generic,
> +				 struct frame_info *frame)
> +{
> +  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> +  return dtrace_probe->probe_argc;
> +}
> +
> +/* Implementation of the can_evaluate_probe_arguments method.  */
> +
> +static int
> +dtrace_can_evaluate_probe_arguments (struct probe *probe_generic)
> +{
> +  struct gdbarch *gdbarch = probe_generic->arch;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +  return gdbarch_dtrace_parse_probe_argument_p (gdbarch);
> +}
> +
> +/* Implementation of the evaluate_probe_argument method.  */
> +
> +static struct value *
> +dtrace_evaluate_probe_argument (struct probe *probe_generic, unsigned n,
> +				struct frame_info *frame)
> +{
> +  struct gdbarch *gdbarch = probe_generic->arch;
> +  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> +  struct dtrace_probe_arg *arg;
> +  int pos = 0;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> +  arg = dtrace_get_arg (dtrace_probe, n, gdbarch);
> +  return evaluate_subexp_standard (arg->type, arg->expr, &pos, EVAL_NORMAL);
> +}
> +
> +/* Implementation of the compile_to_ax method.  */
> +
> +static void
> +dtrace_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr,
> +		      struct axs_value *value, unsigned n)
> +{
> +  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> +  struct dtrace_probe_arg *arg;
> +  union exp_element *pc;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> +  arg = dtrace_get_arg (dtrace_probe, n, expr->gdbarch);
> +
> +  pc = arg->expr->elts;
> +  gen_expr (arg->expr, &pc, expr, value);
> +
> +  require_rvalue (expr, value);
> +  value->type = arg->type;
> +}
> +
> +/* Implementation of the probe_destroy method.  */
> +
> +static void
> +dtrace_probe_destroy (struct probe *probe_generic)
> +{
> +  struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
> +  struct dtrace_probe_arg *arg;
> +  int i;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> +  for (i = 0; VEC_iterate (dtrace_probe_arg_s, probe->args, i, arg); i++)
> +    {
> +      xfree (arg->type_str);
> +      xfree (arg->expr);
> +    }
> +
> +  VEC_free (dtrace_probe_enabler_s, probe->enablers);
> +  VEC_free (dtrace_probe_arg_s, probe->args);
> +}
> +
> +/* Implementation of the type_name method.  */
> +
> +static const char *
> +dtrace_type_name (struct probe *probe_generic)
> +{
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +  return "dtrace";
> +}
> +
> +/* Implementation of the gen_info_probes_table_header method.  */
> +
> +static void
> +dtrace_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
> +{
> +  info_probe_column_s dtrace_probe_column;
> +
> +  dtrace_probe_column.field_name = "enabled";
> +  dtrace_probe_column.print_name = _("Enabled");
> +
> +  VEC_safe_push (info_probe_column_s, *heads, &dtrace_probe_column);
> +}
> +
> +/* Implementation of the gen_info_probes_table_values method.  */
> +
> +static void
> +dtrace_gen_info_probes_table_values (struct probe *probe_generic,
> +				     VEC (const_char_ptr) **ret)
> +{
> +  struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
> +  const char *val = NULL;
> +
> +  gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> +  if (VEC_empty (dtrace_probe_enabler_s, probe->enablers))
> +    val = "always";
> +  else if (!gdbarch_dtrace_probe_is_enabled_p (probe_generic->arch))
> +    val = "unknown";
> +  else if (dtrace_probe_is_enabled (probe))
> +    val = "yes";
> +  else
> +    val = "no";
> +
> +  VEC_safe_push (const_char_ptr, *ret, val);
> +}
> +
> +/* Implementation of the enable_probe method.  */
> +
> +static void
> +dtrace_enable_probe (struct probe *probe)
> +{
> +  struct gdbarch *gdbarch = probe->arch;
> +  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
> +  struct dtrace_probe_enabler *enabler;
> +  int i;
> +
> +  gdb_assert (probe->pops == &dtrace_probe_ops);
> +
> +  /* Enabling a dtrace probe implies patching the text section of the
> +     running process, so make sure the inferior is indeed running.  */
> +  if (ptid_equal (inferior_ptid, null_ptid))
> +    error (_("No inferior running"));
> +
> +  /* Fast path.  */
> +  if (dtrace_probe_is_enabled (dtrace_probe))
> +    return;
> +
> +  /* Iterate over all defined enabler in the given probe and enable
> +     them all using the corresponding gdbarch hook.  */
> +
> +  for (i = 0;
> +       VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
> +       i++)
> +    if (gdbarch_dtrace_enable_probe_p (gdbarch))
> +      gdbarch_dtrace_enable_probe (gdbarch, enabler->address);
> +}
> +
> +
> +/* Implementation of the disable_probe method.  */
> +
> +static void
> +dtrace_disable_probe (struct probe *probe)
> +{
> +  struct gdbarch *gdbarch = probe->arch;
> +  struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
> +  struct dtrace_probe_enabler *enabler;
> +  int i;
> +
> +  gdb_assert (probe->pops == &dtrace_probe_ops);
> +
> +  /* Disabling a dtrace probe implies patching the text section of the
> +     running process, so make sure the inferior is indeed running.  */
> +  if (ptid_equal (inferior_ptid, null_ptid))
> +    error (_("No inferior running"));
> +
> +  /* Fast path.  */
> +  if (!dtrace_probe_is_enabled (dtrace_probe))
> +    return;
> +
> +  /* Are we trying to disable a probe that does not have any enabler
> +     associated?  */
> +  if (VEC_empty (dtrace_probe_enabler_s, dtrace_probe->enablers))
> +    error (_("Probe %s:%s cannot be disabled."), probe->provider, probe->name);

I think it makes sense to say why the probe cannot be disabled (because
there are no enablers associated).

> +
> +  /* Iterate over all defined enabler in the given probe and disable
> +     them all using the corresponding gdbarch hook.  */
> +
> +  for (i = 0;
> +       VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
> +       i++)
> +    {
> +      if (gdbarch_dtrace_disable_probe_p (gdbarch))
> +	gdbarch_dtrace_disable_probe (gdbarch, enabler->address);
> +    }

No need for curly braces.

> +}
> +
> +/* DTrace probe_ops.  */
> +
> +static const struct probe_ops dtrace_probe_ops =
> +{
> +  dtrace_probe_is_linespec,
> +  dtrace_get_probes,
> +  dtrace_get_probe_address,
> +  dtrace_get_probe_argument_count,
> +  dtrace_can_evaluate_probe_arguments,
> +  dtrace_evaluate_probe_argument,
> +  dtrace_compile_to_ax,
> +  NULL, /* set_semaphore  */
> +  NULL, /* clear_semaphore  */
> +  dtrace_probe_destroy,
> +  dtrace_type_name,
> +  dtrace_gen_info_probes_table_header,
> +  dtrace_gen_info_probes_table_values,
> +  dtrace_enable_probe,
> +  dtrace_disable_probe
> +};
> +
> +/* Implementation of the `info probes dtrace' command.  */
> +
> +static void
> +info_probes_dtrace_command (char *arg, int from_tty)
> +{
> +  info_probes_for_ops (arg, from_tty, &dtrace_probe_ops);
> +}
> +
> +void _initialize_dtrace_probe (void);
> +
> +void
> +_initialize_dtrace_probe (void)
> +{
> +  VEC_safe_push (probe_ops_cp, all_probe_ops, &dtrace_probe_ops);
> +
> +  add_cmd ("dtrace", class_info, info_probes_dtrace_command,
> +	   _("\
> +Show information about DTrace static probes.\n\
> +Usage: info probes dtrace [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name."),
> +	   info_probes_cmdlist_get ());
> +}
> -- 
> 1.7.10.4

OK with the requested changes.

Thanks,

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets.
  2015-02-02 10:57 ` [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
@ 2015-02-17  1:37   ` Sergio Durigan Junior
  0 siblings, 0 replies; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:37 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch adds the target-specific code in order to support the
> calculation of DTrace probes arguments in x86_64 targets, and also the
> enabling and disabling of probes.  This is done by implementing the
> `dtrace_*' gdbarch handlers.

Thanks for the patch.  This was approved already; no further comments.  OK.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* amd64-linux-tdep.c: Include "parser-defs.h" and "user-regs.h".
> 	(amd64_dtrace_parse_probe_argument): New function.
> 	(amd64_dtrace_probe_is_enabled): Likewise.
> 	(amd64_dtrace_enable_probe): Likewise.
> 	(amd64_dtrace_disable_probe): Likewise.
> 	(amd64_linux_init_abi): Register the
> 	`gdbarch_dtrace_probe_argument', `gdbarch_dtrace_enable_probe',
> 	`gdbarch_dtrace_disable_probe' and
> 	`gdbarch_dtrace_probe_is_enabled' hooks.
> 	(amd64_dtrace_disabled_probe_sequence_1): New constant.
> 	(amd64_dtrace_disabled_probe_sequence_2): Likewise.
> 	(amd64_dtrace_enable_probe_sequence): Likewise.
> 	(amd64_dtrace_disable_probe_sequence): Likewise.
> ---
>  gdb/ChangeLog          |   16 ++++++
>  gdb/amd64-linux-tdep.c |  148 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 164 insertions(+)
>
> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
> index 42d884e..ffa85f4 100644
> --- a/gdb/amd64-linux-tdep.c
> +++ b/gdb/amd64-linux-tdep.c
> @@ -28,6 +28,8 @@
>  #include "gdbtypes.h"
>  #include "reggroups.h"
>  #include "regset.h"
> +#include "parser-defs.h"
> +#include "user-regs.h"
>  #include "amd64-linux-tdep.h"
>  #include "i386-linux-tdep.h"
>  #include "linux-tdep.h"
> @@ -1643,6 +1645,146 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>        &amd64_linux_xstateregset, "XSAVE extended state", cb_data);
>  }
>  
> +/* The instruction sequences used in x86_64 machines for a
> +   disabled is-enabled probe.  */
> +
> +const gdb_byte amd64_dtrace_disabled_probe_sequence_1[] = {
> +  /* xor %rax, %rax */  0x48, 0x33, 0xc0,
> +  /* nop            */  0x90,
> +  /* nop            */  0x90
> +};
> +
> +const gdb_byte amd64_dtrace_disabled_probe_sequence_2[] = {
> +  /* xor %rax, %rax */  0x48, 0x33, 0xc0,
> +  /* ret            */  0xc3,
> +  /* nop            */  0x90
> +};
> +
> +/* The instruction sequence used in x86_64 machines for enabling a
> +   DTrace is-enabled probe.  */
> +
> +const gdb_byte amd64_dtrace_enable_probe_sequence[] = {
> +  /* mov $0x1, %eax */ 0xb8, 0x01, 0x00, 0x00, 0x00
> +};
> +
> +/* The instruction sequence used in x86_64 machines for disabling a
> +   DTrace is-enabled probe.  */
> +
> +const gdb_byte amd64_dtrace_disable_probe_sequence[] = {
> +  /* xor %rax, %rax; nop; nop */ 0x48, 0x33, 0xC0, 0x90, 0x90
> +};
> +
> +/* Implementation of `gdbarch_dtrace_probe_is_enabled', as defined in
> +   gdbarch.h.  */
> +
> +static int
> +amd64_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  gdb_byte buf[5];
> +
> +  /* This function returns 1 if the instructions at ADDR do _not_
> +     follow any of the amd64_dtrace_disabled_probe_sequence_*
> +     patterns.
> +
> +     Note that ADDR is offset 3 bytes from the beginning of these
> +     sequences.  */
> +  
> +  read_code (addr - 3, buf, 5);
> +  return (memcmp (buf, amd64_dtrace_disabled_probe_sequence_1, 5) != 0
> +	  && memcmp (buf, amd64_dtrace_disabled_probe_sequence_2, 5) != 0);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_enable_probe', as defined in
> +   gdbarch.h.  */
> +
> +static void
> +amd64_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  /* Note also that ADDR is offset 3 bytes from the beginning of
> +     amd64_dtrace_enable_probe_sequence.  */
> +
> +  write_memory (addr - 3, amd64_dtrace_enable_probe_sequence, 5);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_disable_probe', as defined in
> +   gdbarch.h.  */
> +
> +static void
> +amd64_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  /* Note also that ADDR is offset 3 bytes from the beginning of
> +     amd64_dtrace_disable_probe_sequence.  */
> +
> +  write_memory (addr - 3, amd64_dtrace_disable_probe_sequence, 5);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_parse_probe_argument', as defined
> +   in gdbarch.h.  */
> +
> +static void
> +amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
> +				   struct parser_state *pstate,
> +				   int narg)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  struct frame_info *this_frame = get_selected_frame (NULL);
> +  struct stoken str;
> +
> +  /* DTrace probe arguments can be found on the ABI-defined places for
> +     regular arguments at the current PC.  The probe abstraction
> +     currently supports up to 12 arguments for probes.  */
> +
> +  if (narg < 6)
> +    {
> +      static const int arg_reg_map[6] =
> +	{
> +	  AMD64_RDI_REGNUM,  /* Arg 1.  */
> +	  AMD64_RSI_REGNUM,  /* Arg 2.  */
> +	  AMD64_RDX_REGNUM,  /* Arg 3.  */
> +	  AMD64_RCX_REGNUM,  /* Arg 4.  */
> +	  AMD64_R8_REGNUM,   /* Arg 5.  */
> +	  AMD64_R9_REGNUM    /* Arg 6.  */
> +	};
> +      int regno = arg_reg_map[narg];
> +      const char *regname = user_reg_map_regnum_to_name (gdbarch, regno);
> +
> +      write_exp_elt_opcode (pstate, OP_REGISTER);
> +      str.ptr = regname;
> +      str.length = strlen (regname);
> +      write_exp_string (pstate, str);
> +      write_exp_elt_opcode (pstate, OP_REGISTER);
> +    }
> +  else
> +    {
> +      /* Additional arguments are passed on the stack.  */
> +      CORE_ADDR sp;
> +      const char *regname = user_reg_map_regnum_to_name (gdbarch, AMD64_RSP_REGNUM);
> +
> +      /* Displacement.  */
> +      write_exp_elt_opcode (pstate, OP_LONG);
> +      write_exp_elt_type (pstate, builtin_type (gdbarch)->builtin_long);
> +      write_exp_elt_longcst (pstate, narg - 6);
> +      write_exp_elt_opcode (pstate, OP_LONG);
> +
> +      /* Register: SP.  */
> +      write_exp_elt_opcode (pstate, OP_REGISTER);
> +      str.ptr = regname;
> +      str.length = strlen (regname);
> +      write_exp_string (pstate, str);
> +      write_exp_elt_opcode (pstate, OP_REGISTER);
> +
> +      write_exp_elt_opcode (pstate, BINOP_ADD);
> +
> +      /* Cast to long. */
> +      write_exp_elt_opcode (pstate, UNOP_CAST);
> +      write_exp_elt_type (pstate,
> +			  lookup_pointer_type (builtin_type (gdbarch)->builtin_long));
> +      write_exp_elt_opcode (pstate, UNOP_CAST);
> +
> +      write_exp_elt_opcode (pstate, UNOP_IND);
> +    }
> +}
> +
>  static void
>  amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
>  {
> @@ -1907,6 +2049,12 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>    /* GNU/Linux uses SVR4-style shared libraries.  */
>    set_solib_svr4_fetch_link_map_offsets
>      (gdbarch, svr4_lp64_fetch_link_map_offsets);
> +
> +  /* Register DTrace handlers.  */
> +  set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
> +  set_gdbarch_dtrace_probe_is_enabled (gdbarch, amd64_dtrace_probe_is_enabled);
> +  set_gdbarch_dtrace_enable_probe (gdbarch, amd64_dtrace_enable_probe);
> +  set_gdbarch_dtrace_disable_probe (gdbarch, amd64_dtrace_disable_probe);
>  }
>  
>  static void
> -- 
> 1.7.10.4

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 7/9] Simple testsuite for DTrace USDT probes.
  2015-02-02 10:57 ` [PATCH V4 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
  2015-02-02 11:18   ` Jose E. Marchesi
@ 2015-02-17  1:53   ` Sergio Durigan Junior
  2015-02-17  1:58     ` Sergio Durigan Junior
  1 sibling, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:53 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch adds some simple tests testing the support for DTrace USDT
> probes.  The testsuite will be skipped as unsupported in case the user
> does not have DTrace installed on her system.  The tests included in the
> test suite test breakpointing on DTrace probes, enabling and disabling
> probes, printing of probe arguments of several types and also
> breakpointing on several probes with the same name.

Thanks again for this awesome testcase.  I don't have any more comments
to make about the patch itself; I personally liked your way of solving
the transform problem, though I have a preference to see those changes
in a different patch (i.e., not in the DTrace series).  Do you think you
can do that?  It should be really easy to extract this part from your
patch; and then, you'd only have to worry about the dtrace-side of it.

I can't give you an approval for the transform.m4 thing, but for the
rest, you have an OK.

Thanks,

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* Makefile.in (aclocal_m4_deps): Added transform.m4.
> 	* acinclude.m4: sinclude transform.m4.
> 	* transform.m4 (GDB_AC_TRANSFORM): New macro.
> 	New file.
> 	* configure.ac: Use GDB_AC_TRANSFORM.
>
> gdb/testsuite/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* lib/dtrace.exp: New file.
> 	* gdb.base/dtrace-probe.exp: Likewise.
> 	* gdb.base/dtrace-probe.d: Likewise.
> 	* gdb.base/dtrace-probe.c: Likewise.
> 	* lib/pdtrace.in: Likewise.
> 	* configure.ac: Output variables with the transformed names of
> 	the strip, readelf, as and nm tools.  AC_SUBST lib/pdtrace.in.
> 	* configure: Regenerated.
> 	* aclocal.m4: sinclude ../transform.m4.
> ---
>  gdb/ChangeLog                           |    8 +
>  gdb/Makefile.in                         |    1 +
>  gdb/acinclude.m4                        |    3 +
>  gdb/configure                           |   24 +-
>  gdb/configure.ac                        |   14 +-
>  gdb/testsuite/ChangeLog                 |   12 +
>  gdb/testsuite/aclocal.m4                |    1 +
>  gdb/testsuite/configure                 |   62 ++
>  gdb/testsuite/configure.ac              |    9 +
>  gdb/testsuite/gdb.base/dtrace-probe.c   |   38 ++
>  gdb/testsuite/gdb.base/dtrace-probe.d   |   21 +
>  gdb/testsuite/gdb.base/dtrace-probe.exp |  106 ++++
>  gdb/testsuite/lib/dtrace.exp            |   71 +++
>  gdb/testsuite/lib/pdtrace.in            | 1033 +++++++++++++++++++++++++++++++
>  14 files changed, 1381 insertions(+), 22 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
>  create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
>  create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
>  create mode 100644 gdb/testsuite/lib/dtrace.exp
>  create mode 100755 gdb/testsuite/lib/pdtrace.in
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index e933b45..c376f44 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1527,6 +1527,7 @@ aclocal_m4_deps = \
>  	configure.ac \
>  	acx_configure_dir.m4 \
>  	libmcheck.m4 \
> +	transform.m4 \
>  	../bfd/bfd.m4 \
>  	../config/acinclude.m4 \
>  	../config/plugins.m4 \
> diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
> index 6f71486..1f0b574 100644
> --- a/gdb/acinclude.m4
> +++ b/gdb/acinclude.m4
> @@ -9,6 +9,9 @@ sinclude(acx_configure_dir.m4)
>  # This gets GDB_AC_LIBMCHECK.
>  sinclude(libmcheck.m4)
>  
> +# This gets GDB_AC_TRANSFORM.
> +sinclude(transform.m4)
> +
>  dnl gdb/configure.in uses BFD_NEED_DECLARATION, so get its definition.
>  sinclude(../bfd/bfd.m4)
>  
> diff --git a/gdb/configure b/gdb/configure
> index 30a54d2..bb9697d 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -15141,17 +15141,21 @@ ac_config_links="$ac_config_links $ac_config_links_1"
>  $as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
>  
>  
> -# Undo the $ec_script escaping suitable for Makefile.
> -transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> -GDB_TRANSFORM_NAME=`echo gdb | sed -e "$transform"`
> -if test "x$GDB_TRANSFORM_NAME" = x; then
> -  GDB_TRANSFORM_NAME=gdb
> -fi
>  
> -GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$transform"`
> -if test "x$GCORE_TRANSFORM_NAME" = x; then
> -  GCORE_TRANSFORM_NAME=gcore
> -fi
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  GDB_TRANSFORM_NAME=`echo gdb | sed -e "$gdb_ac_transform"`
> +  if test "x$GDB_TRANSFORM_NAME" = x; then
> +     GDB_TRANSFORM_NAME=gdb
> +  fi
> +
> +
> +
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$gdb_ac_transform"`
> +  if test "x$GCORE_TRANSFORM_NAME" = x; then
> +     GCORE_TRANSFORM_NAME=gcore
> +  fi
> +
>  
>  ac_config_files="$ac_config_files gcore"
>  
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 39fcef2..90bf71c 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -2444,18 +2444,8 @@ dnl  At the moment, we just assume it's UTF-8.
>  AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8",
>            [Define to be a string naming the default host character set.])
>  
> -# Undo the $ec_script escaping suitable for Makefile.
> -transform=`echo "$program_transform_name" | sed -e 's/[\\$][\\$]/\\$/g'`
> -GDB_TRANSFORM_NAME=`echo gdb | sed -e "$transform"`
> -if test "x$GDB_TRANSFORM_NAME" = x; then
> -  GDB_TRANSFORM_NAME=gdb
> -fi
> -AC_SUBST(GDB_TRANSFORM_NAME)
> -GCORE_TRANSFORM_NAME=`echo gcore | sed -e "$transform"`
> -if test "x$GCORE_TRANSFORM_NAME" = x; then
> -  GCORE_TRANSFORM_NAME=gcore
> -fi
> -AC_SUBST(GCORE_TRANSFORM_NAME)
> +GDB_AC_TRANSFORM([gdb], [GDB_TRANSFORM_NAME])
> +GDB_AC_TRANSFORM([gcore], [GCORE_TRANSFORM_NAME])
>  AC_CONFIG_FILES([gcore], [chmod +x gcore])
>  
>  AC_OUTPUT(Makefile gdb-gdb.gdb doc/Makefile data-directory/Makefile,
> diff --git a/gdb/testsuite/aclocal.m4 b/gdb/testsuite/aclocal.m4
> index 2934db2..d40c3a9 100644
> --- a/gdb/testsuite/aclocal.m4
> +++ b/gdb/testsuite/aclocal.m4
> @@ -1,5 +1,6 @@
>  sinclude(../../config/acx.m4)
>  sinclude(../../config/override.m4)
> +sinclude(../transform.m4)
>  
>  # AM_CONDITIONAL                                            -*- Autoconf -*-
>  
> diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
> index ca033c3..f36a1bd 100755
> --- a/gdb/testsuite/configure
> +++ b/gdb/testsuite/configure
> @@ -591,6 +591,10 @@ ac_includes_default="\
>  
>  ac_subst_vars='LTLIBOBJS
>  LIBOBJS
> +NM_TRANSFORM_NAME
> +GAS_TRANSFORM_NAME
> +READELF_TRANSFORM_NAME
> +STRIP_TRANSFORM_NAME
>  EXTRA_RULES
>  EGREP
>  GREP
> @@ -1272,6 +1276,11 @@ _ACEOF
>  
>    cat <<\_ACEOF
>  
> +Program names:
> +  --program-prefix=PREFIX            prepend PREFIX to installed program names
> +  --program-suffix=SUFFIX            append SUFFIX to installed program names
> +  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
> +
>  System types:
>    --build=BUILD     configure for building on BUILD [guessed]
>    --host=HOST       cross-compile to build programs to run on HOST [BUILD]
> @@ -3458,6 +3467,53 @@ if test "${build}" = "${host}" -a "${host}" = "${target}"; then
>  fi
>  
>  
> +# Transform the name of some programs and generate the lib/pdtrace
> +# test tool.
> +test "$program_prefix" != NONE &&
> +  program_transform_name="s&^&$program_prefix&;$program_transform_name"
> +# Use a double $ so make ignores it.
> +test "$program_suffix" != NONE &&
> +  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
> +# Double any \ or $.
> +# By default was `s,x,x', remove it if useless.
> +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
> +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
> +
> +
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  STRIP_TRANSFORM_NAME=`echo strip | sed -e "$gdb_ac_transform"`
> +  if test "xSTRIP_TRANSFORM_NAME" = x; then
> +     STRIP_TRANSFORM_NAME=strip
> +  fi
> +
> +
> +
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  READELF_TRANSFORM_NAME=`echo readelf | sed -e "$gdb_ac_transform"`
> +  if test "xREADELF_TRANSFORM_NAME" = x; then
> +     READELF_TRANSFORM_NAME=readelf
> +  fi
> +
> +
> +
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  GAS_TRANSFORM_NAME=`echo as | sed -e "$gdb_ac_transform"`
> +  if test "xGAS_TRANSFORM_NAME" = x; then
> +     GAS_TRANSFORM_NAME=as
> +  fi
> +
> +
> +
> +  gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
> +  NM_TRANSFORM_NAME=`echo nm | sed -e "$gdb_ac_transform"`
> +  if test "xNM_TRANSFORM_NAME" = x; then
> +     NM_TRANSFORM_NAME=nm
> +  fi
> +
> +
> +ac_config_files="$ac_config_files lib/pdtrace"
> +
> +
>  ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile gdb.cell/Makefile gdb.compile/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.dlang/Makefile gdb.fortran/Makefile gdb.gdb/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.guile/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.perf/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
>  
>  cat >confcache <<\_ACEOF
> @@ -4158,6 +4214,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
>  for ac_config_target in $ac_config_targets
>  do
>    case $ac_config_target in
> +    "lib/pdtrace") CONFIG_FILES="$CONFIG_FILES lib/pdtrace" ;;
>      "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
>      "gdb.ada/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.ada/Makefile" ;;
>      "gdb.arch/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.arch/Makefile" ;;
> @@ -4599,6 +4656,11 @@ which seems to be undefined.  Please make sure it is defined." >&2;}
>  
>    esac
>  
> +
> +  case $ac_file$ac_mode in
> +    "lib/pdtrace":F) chmod +x lib/pdtrace ;;
> +
> +  esac
>  done # for ac_tag
>  
>  
> diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
> index 5037723..9de9fcc 100644
> --- a/gdb/testsuite/configure.ac
> +++ b/gdb/testsuite/configure.ac
> @@ -96,6 +96,15 @@ if test "${build}" = "${host}" -a "${host}" = "${target}"; then
>  fi
>  AC_SUBST(EXTRA_RULES)
>  
> +# Transform the name of some programs and generate the lib/pdtrace
> +# test tool.
> +AC_ARG_PROGRAM
> +GDB_AC_TRANSFORM(strip, STRIP_TRANSFORM_NAME)
> +GDB_AC_TRANSFORM(readelf, READELF_TRANSFORM_NAME)
> +GDB_AC_TRANSFORM(as, GAS_TRANSFORM_NAME)
> +GDB_AC_TRANSFORM(nm, NM_TRANSFORM_NAME)
> +AC_CONFIG_FILES([lib/pdtrace], [chmod +x lib/pdtrace])
> +
>  AC_OUTPUT([Makefile \
>    gdb.ada/Makefile \
>    gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile \
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.c b/gdb/testsuite/gdb.base/dtrace-probe.c
> new file mode 100644
> index 0000000..29933ad
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.c
> @@ -0,0 +1,38 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014, 2015 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/>.  */
> +
> +#include "dtrace-probe.h"
> +
> +int
> +main ()
> +{
> +  char *name = "application";
> +
> +  TEST_TWO_LOCATIONS ();
> +  
> +  int i = 0;
> +  while (i < 10)
> +    {
> +      i++;
> +      if (TEST_PROGRESS_COUNTER_ENABLED ())
> +	TEST_PROGRESS_COUNTER (name, i);
> +      else
> +	TEST_TWO_LOCATIONS ();
> +    }
> +      
> +  return 0; /* last break here */
> +}
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.d b/gdb/testsuite/gdb.base/dtrace-probe.d
> new file mode 100644
> index 0000000..6bcbf34
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.d
> @@ -0,0 +1,21 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014, 2015 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/>.  */
> +
> +provider test {
> +  probe progress__counter (char *, int);
> +  probe two__locations  ();
> +};
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.exp b/gdb/testsuite/gdb.base/dtrace-probe.exp
> new file mode 100644
> index 0000000..e42e948
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.exp
> @@ -0,0 +1,106 @@
> +# Copyright (C) 2014, 2015 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 "dtrace.exp"
> +
> +# Run the tests.
> +# This returns -1 on failure to compile or start, 0 otherwise.
> +proc dtrace_test {} {
> +    global testfile hex srcfile binfile
> +
> +    standard_testfile
> +    
> +    if {[dtrace_build_usdt_test_program] == -1} {
> +        untested "could not compile test program"
> +        return -1
> +    }
> +
> +    clean_restart ${binfile}
> +    
> +    if ![runto_main] {
> +        return -1
> +    }
> +
> +    gdb_test "print \$_probe_argc" "No probe at PC $hex" \
> +        "check argument not at probe point"
> +
> +    # Test the 'info probes' command.
> +    gdb_test "info probes dtrace" \
> +        "test *progress-counter *$hex +no.*test *two-locations *$hex +always.*test *two-locations *$hex +always.*" \
> +        "info probes dtrace"
> +
> +    # Disabling the probe test:two-locations shall have no effect,
> +    # since no is-enabled probes are defined for it in the object
> +    # file.
> +
> +    gdb_test "disable probe test two-locations" \
> +	"Probe test:two-locations cannot be disabled.*" \
> +	"disable probe test two-locations"
> +
> +    # On the other hand, the probe test:progress-counter can be
> +    # enabled and then disabled again.
> +
> +    gdb_test "enable probe test progress-counter" \
> +	"Probe test:progress-counter enabled.*" \
> +	"enable probe test progress-counter"
> +
> +    gdb_test "disable probe test progress-counter" \
> +	"Probe test:progress-counter disabled.*" \
> +	"disable probe test progress-counter"
> +
> +    # Since test:progress-counter is disabled we can run to the second
> +    # instance of the test:two-locations probe.
> +
> +    if {![runto "-probe-dtrace test:two-locations"]} {
> +	fail "run to the first test:two-locations probe point"
> +    }
> +    if {![runto "-probe-dtrace test:two-locations"]} {
> +	fail "run to the second test:two-locations probe point"
> +    }
> +
> +    # Go back to the breakpoint on main() and enable the
> +    # test:progress-counter probe.  Set a breakpoint on it and see
> +    # that it gets reached.
> +
> +    if ![runto_main] {
> +	return -1
> +    }
> +
> +    gdb_test "enable probe test progress-counter" \
> +	"Probe test:progress-counter enabled.*" \
> +	"enable probe test progress-counter"
> +
> +    gdb_test "break -probe-dtrace test:progress-counter" \
> +	".*Breakpoint \[0-9\]+ .*" "set breakpoint in test:progress-counter"
> +    gdb_continue_to_breakpoint "test:progress-counter"
> +
> +    # Test probe arguments.
> +    gdb_test "print \$_probe_argc" " = 2" \
> +        "print \$_probe_argc for probe progress-counter"
> +    gdb_test "print \$_probe_arg0" \
> +        " = $hex \"application\"" \
> +        "print \$_probe_arg0 for probe progress-counter"
> +    gdb_test "print \$_probe_arg1" " = 1" \
> +        "print \$_probe_arg1 for probe progress-counter"
> +
> +    # Set a breakpoint with multiple probe locations.
> +    gdb_test "break -pdtrace test:two-locations" \
> +        "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
> +        "set multi-location probe breakpoint (probe two-locations)"
> +
> +    return 0
> +}
> +
> +dtrace_test
> diff --git a/gdb/testsuite/lib/dtrace.exp b/gdb/testsuite/lib/dtrace.exp
> new file mode 100644
> index 0000000..e323b08
> --- /dev/null
> +++ b/gdb/testsuite/lib/dtrace.exp
> @@ -0,0 +1,71 @@
> +# Copyright 2014, 2015 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/>.
> +
> +# Generate a test program containing DTrace USDT probes, whose sources
> +# are ${srcfile} and ${testfile}.d.  The sequence of commands used to
> +# generate the test program is:
> +#
> +# 1. Generate a header file from ${testfile}.d using dtrace -h.
> +# 2. Compile ${srcfile}.c.
> +# 3. Generate an object file containing a DOF program using dtrace -G.
> +# 4. Link everything together to get the test program.
> +#
> +# Note that if DTrace is not found in the host system then this
> +# function uses the pdtrace implementation, which is located at
> +# testsuite/lib/pdtrace.
> +#
> +# This function requires 'testfile', 'srcfile' and 'binfile' to be
> +# properly set.
> +#
> +# This function returns -1 on failure, 0 otherwise
> +proc dtrace_build_usdt_test_program {} {
> +    global testfile hex objdir srcdir srcfile subdir binfile
> +    
> +    # Make sure that dtrace is installed, it is the real one (not the
> +    # script installed by SystemTap, for example) and of the right
> +    # version (>= 0.4.0).  If it is not then use pdtrace instead.
> +    set dtrace "dtrace"
> +    set result [remote_exec host "$dtrace -V"]
> +    if {[lindex $result 0] != 0 || ![regexp {^dtrace: Sun D [0-9]\.[0-9]\.[0-9]} [lindex $result 1]]} {
> +	set dtrace "${objdir}/lib/pdtrace"
> +    }
> +    set dscript_file "${srcdir}/${subdir}/${testfile}.d"
> +
> +    # 1. Generate a header file from testprogram.d using dtrace -h.
> +    set out_header_file [standard_output_file "${testfile}.h"]
> +    set result [remote_exec host "$dtrace -h -s $dscript_file -o $out_header_file"]
> +    verbose -log [lindex $result 1]
> +    if {[lindex $result 0] != 0} {
> +        return -1
> +    }
> +
> +    # 2. Compile testprogram.c.
> +    set options [list debug additional_flags=-I[file dirname $out_header_file]]
> +    if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}.o" object ${options}] != ""} {
> +        return -1
> +    }
> +
> +    # 3. Generate an object file containing a DOF program using dtrace -G.
> +    set result [remote_exec host "$dtrace -G -s $dscript_file -o ${binfile}-p.o ${binfile}.o"]
> +    verbose -log [lindex $result 1]
> +    if {[lindex $result 0] != 0} {
> +        return -1
> +    }
> +
> +    # 4. Link everything together to get the test program.
> +    if {[gdb_compile "${binfile}.o ${binfile}-p.o" ${binfile} executable {debug}] != ""} {
> +        return -1
> +    }
> +}
> diff --git a/gdb/testsuite/lib/pdtrace.in b/gdb/testsuite/lib/pdtrace.in
> new file mode 100755
> index 0000000..118b017
> --- /dev/null
> +++ b/gdb/testsuite/lib/pdtrace.in
> @@ -0,0 +1,1033 @@
> +#!/bin/sh
> +
> +# A Poor(but Free)'s Man dtrace
> +#
> +# Copyright (C) 2014, 2015 Free Software Foundation, Inc.
> +#
> +# Contributed by Oracle, Inc.
> +#
> +# This file is part of GDB.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful, but
> +# WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +# General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see
> +# <http://www.gnu.org/licenses/>.
> +
> +# DISCLAIMER DISCLAIMER DISCLAIMER
> +# This script is a test tool.  As such it is in no way intended to
> +# replace the "real" dtrace command for any practical purpose, apart
> +# from testing the DTrace USDT probes support in GDB.
> +
> +# that said...
> +#
> +# pdtrace is a limited dtrace program, implementing a subset of its
> +# functionality:
> +#
> +# - The generation of an ELF file containing an embedded dtrace
> +#   program.  Equivalent to dtrace -G.
> +#
> +# - The generation of a header file with definitions for static
> +#   probes.  Equivalent to dtrace -h.
> +#
> +# This allows to generate DTrace static probes without having to use
> +# the user-level DTrace components.  The generated objects are 100%
> +# compatible with DTrace and can be traced by the dtrace kernel module
> +# like if they were generated by dtrace.
> +#
> +# Some of the known limitations of this implementation are:
> +# - The input d-script must describe one provider, and only one.
> +# - The "probe " directives in the d-file must not include argument
> +#   names, just the types.  Thus something like `char *' is valid, but
> +#   `char *name' is not.
> +# - The command line options must precede other arguments, since the
> +#   script uses the (more) portable getopts.
> +# - Each probe header in the d-script must be contained in
> +#   a single line.
> +# - strip -K removes the debugging information from the input object
> +#   file.
> +# - The supported target platforms are i[3456]86 and x86_64.
> +#
> +# Please keep this code as portable as possible.  Restrict yourself to
> +# POSIX sh.
> +
> +# This script uses the following external programs, defined in
> +# variables.  Some of them are substituted by autoconf.
> +
> +TR=tr
> +NM=@NM_TRANSFORM_NAME@
> +EGREP=egrep
> +SED=sed
> +CUT=cut
> +READELF=@READELF_TRANSFORM_NAME@
> +SORT=sort
> +EXPR=expr
> +WC=wc
> +UNIQ=uniq
> +HEAD=head
> +SEQ=seq
> +AS=@GAS_TRANSFORM_NAME@
> +STRIP=@STRIP_TRANSFORM_NAME@
> +TRUE=true
> +
> +# Sizes for several DOF structures, in bytes.
> +#
> +# See linux/dtrace/dof.h for the definition of the referred
> +# structures.
> +
> +dof_hdrsize=64      # sizeof(dtrace_dof_hdr)
> +dof_secsize=32      # sizeof(dtrace_dof_sect)
> +dof_probesize=48    # sizeof(dtrace_dof_probe)
> +dof_providersize=44 # sizeof(dtrace_dof_provider)
> +
> +# Types for the several DOF sections.
> +#
> +# See linux/dtrace/dof_defines.h for a complete list of section types
> +# along with their values.
> +
> +dof_sect_type_strtab=8
> +dof_sect_type_provider=15
> +dof_sect_type_probes=16
> +dof_sect_type_prargs=17
> +dof_sect_type_proffs=18
> +dof_sect_type_prenoffs=26
> +
> +### Functions
> +
> +# Write a message to the standard error output and exit with an error
> +# status.
> +#
> +# Arguments:
> +#   $1 error message.
> +
> +f_panic()
> +{
> +    echo "error: $1" 1>&2; exit 1
> +}
> +
> +# Write a usage message to the standard output and exit with an error
> +# status.
> +
> +f_usage()
> +{
> +    printf "Usage: pdtrace [-32|-64] [-GhV] [-o output] [-s script] [ args ... ]\n\n"
> +
> +    printf "\t-32 generate 32-bit ELF files\n"
> +    printf "\t-64 generate 64-bit ELF files\n\n"
> +
> +    printf "\t-G  generate an ELF file containing embedded dtrace program\n"
> +    printf "\t-h  generate a header file with definitions for static probes\n"
> +    printf "\t-o  set output file\n"
> +    printf "\t-s  handle probes according to the specified D script\n"
> +    printf "\t-V  report the DTrace API version implemented by the tool\n"
> +    exit 2
> +}
> +
> +# Write a version message to the standard output and exit with a
> +# successful status.
> +
> +f_version()
> +{
> +    echo "pdtrace: Sun D 1.6.3"
> +    exit
> +}
> +
> +# Add a new record to a list and return it.
> +#
> +# Arguments:
> +# $1 is the list.
> +# $2 is the new record
> +
> +f_add_record()
> +{
> +    rec=$1
> +    test -n "$rec" && \
> +        { rec=$(printf %s\\n "$rec"; echo x); rec=${rec%x}; }
> +    printf %s "$rec$2"
> +}
> +
> +# Collect the providers and probes information from the input object
> +# file.
> +#
> +# This function sets the values of the following global variables.
> +# The values are structured in records, each record in a line.  The
> +# fields of each record are separated in some cases by white
> +# characters and in other cases by colon (:) characters.
> +#
> +# The type codes in the line format descriptors are:
> +# S: string, D: decimal number
> +#
> +# probes
> +#   Regular probes and is-enabled probes.
> +#   TYPE(S) PROVIDER(S) NAME(S) OFFSET(D) BASE(D) BASE_SYM(S)
> +# base_probes
> +#   Base probes, i.e. probes sharing provider, name and container.
> +#   PROVIDER(S) NAME(S) BASE(D) BASE_SYM(S)
> +# providers
> +#   List of providers.
> +#   PROVIDER(S)
> +# All the offsets are expressed in bytes.
> +#
> +# Input globals:
> +#  objfile
> +# Output globals:
> +#  probes, base_probes, providers
> +
> +probes=
> +base_probes=
> +providers=
> +probes_args=
> +
> +f_collect_probes()
> +{
> +    # Probe points are function calls to undefined functions featuring
> +    # distinct names for both normal probes and is-enabled probes.
> +    PROBE_REGEX="(__dtrace_([a-zA-Z_]+)___([a-zA-Z_]+))"
> +    EPROBE_REGEX="(__dtraceenabled_([a-zA-Z_]+)___([a-zA-Z_]+))"
> +
> +    while read type symbol provider name; do
> +          test -z "$type" && f_panic "No probe points found in $objfile"
> +
> +          provider=$(printf %s $provider | $TR -s _)
> +          name=$(printf %s $name | $TR -s _)
> +
> +          # Search the object file for relocations defined for the
> +          # probe symbols.  Then calculate the base address of the
> +          # probe (along with the symbol associated with that base
> +          # address) and the offset of the probe point.
> +          for offset in $($READELF -W -r $objfile | $EGREP $symbol | $CUT -d' ' -f1)
> +          do
> +              # Figure out the base address for the probe.  This is
> +              # done finding the function name in the text section of
> +              # the object file located above the probed point.  But
> +              # note that the relocation is for the address operand of
> +              # the call instruction, so we have to subtract 1 to find
> +              # the real probed point.
> +              offset=$((0x$offset - 1))
> +
> +              # The addresses of is-enabled probes must point to the
> +              # first NOP instruction in their patched instructions
> +              # sequences, so modify them (see f_patch_objfile for the
> +              # instruction sequences).
> +              if test "$type" = "e"; then
> +                  if test "$objbits" -eq "32"; then
> +                      offset=$((offset + 2))
> +                  else # 64 bits
> +                      offset=$((offset + 3))
> +                  fi
> +              fi
> +              
> +              # Determine the base address of the probe and its
> +              # corresponding function name.
> +              funcs=$($NM -td $objfile | $EGREP "^[0-9]+ T " \
> +                      | $CUT -d' ' -f1,3 | $SORT -n -r | $TR ' ' :)
> +              for fun in $funcs; do
> +                  func_off=$(printf %s $fun | $CUT -d: -f1)
> +                  func_sym=$(printf %s $fun | $CUT -d: -f2)
> +                  # Note that `expr' is used to remove leading zeros
> +                  # to avoid FUNC_OFF to be interpreted as an octal
> +                  # number in arithmetic contexts.
> +                  test "$func_off" -le "$offset" && \
> +                      { base=$($EXPR $func_off + 0); break; }
> +              done
> +              test -n "$base" || \
> +                f_panic "could not find base address for probe at $objfile($o)"
> +
> +              # Emit the record for the probe.
> +              probes=$(f_add_record "$probes" \
> +                                    "$type $provider $name $(($offset - $base)) $base $func_sym")
> +          done
> +      done <<EOF
> +$($NM $objfile | $EGREP " U $PROBE_REGEX" \
> +            | $SED -E -e "s/.*$PROBE_REGEX.*/p \1 \2 \3/";
> +     $NM $objfile | $EGREP " U $EPROBE_REGEX" \
> +         | $SED -E -e "s/.*$EPROBE_REGEX.*/e \1 \2 \3/")
> +EOF
> +
> +    # Build the list of providers and of base probes from the probes.
> +    while read type provider name offset base base_sym; do
> +        providers=$(f_add_record "$providers" "$provider")
> +        base_probes=$(f_add_record "$base_probes" "$provider $name $base $base_sym")
> +    done <<EOF
> +$probes
> +EOF
> +    providers=$(printf %s\\n "$providers" | $SORT | $UNIQ)
> +    base_probes=$(printf %s\\n "$base_probes" | $SORT | $UNIQ)
> +}
> +
> +# Collect the argument counts and type strings for all the probes
> +# described in the `probes' global variable.  This is done by
> +# inspecting the d-script file provided by the user.
> +#
> +# This function sets the values of the following global variables.
> +# The values are structured in records, each record in a line.  The
> +# fields of each record are separated in some cases by white
> +# characters and in other cases by colon (:) characters.
> +#
> +# The type codes in the line format descriptors are:
> +# S: string, D: decimal number
> +#
> +# probes_args
> +#   Probes arguments.
> +#   PROVIDER(S):NAME(S):NARGS(D):ARG1(S):ARG2(S):...:ARGn(S)
> +#
> +# Input globals:
> +#  probes
> +# Output globals:
> +#  probes_args
> +# Arguments:
> +#   $1 is the d-script file from which to extract the arguments
> +#      information.
> +
> +f_collect_probes_args()
> +{
> +    dscript=$1
> +    while read type provider name offset base base_sym; do
> +        # Process normal probes only.  Is-enabled probes are not
> +        # described in the d-script file and they don't receive any
> +        # argument.
> +        test "$type" = "p" || continue
> +        
> +        # Names are mangled in d-script files to make it possible to
> +        # have underscore characters as part of the provider name and
> +        # probe name.
> +        m_provider=$(printf %s $provider | $SED -e 's/_/__/g')
> +        m_name=$(printf %s $name | $SED -e 's/_/__/g')
> +        
> +        # Ignore this probe if the d-script file does not describe its
> +        # provider.
> +        $EGREP -q "provider +$m_provider" $dscript || continue
> +        
> +        # Look for the line containing the description of the probe.
> +        # If we can't find it then ignore this probe.
> +        line=$($EGREP "^ *probe +$m_name *\(.*\);" $dscript)
> +        test -n "$line" || continue
> +        
> +        # Ok, extract the argument types from the probe prototype.
> +        # This is fragile as hell as it requires the prototype to be
> +        # in a single line.
> +        args=""; nargs=0; line=$(printf %s "$line" | $SED -e 's/.*(\(.*\)).*/\1/')
> +        set -f; IFS=,
> +        for arg in $line; do
> +            args="$args:$arg"
> +            nargs=$((nargs + 1))
> +        done
> +        set +f; unset IFS
> +
> +        # Emit the record for the probe arguments.
> +        probes_args=$(f_add_record "$probes_args" "$provider:$name:$nargs$args")
> +    done <<EOF
> +$probes
> +EOF
> +}
> +
> +# Functions to manipulate the global BCOUNT.
> +
> +BCOUNT=0
> +
> +f_incr_bcount()
> +{
> +    BCOUNT=$((BCOUNT + $1))
> +}
> +
> +f_align_bcount()
> +{
> +    test $((BCOUNT % $1)) -eq 0 || BCOUNT=$((BCOUNT + ($1 - (BCOUNT % $1))))
> +}
> +
> +# Generate a line of assembly code and add it to the asmprogram global
> +# variable.
> +#
> +# Arguments:
> +#   $1 string to generate in a line.
> +
> +asmprogram=
> +
> +f_gen_asm()
> +{
> +    line=$(printf "\t$1")
> +    asmprogram=$(f_add_record "$asmprogram" "$line")
> +}
> +
> +# Helper function to generate the assembly code of a DOF section
> +# header.
> +#
> +# This function is used by `f_gen_dof_program'.
> +#
> +# Arguments:
> +#   $1 is the name of the described section.
> +#   $2 is the type of the described section.
> +#   $3 is the alignment of the described section.
> +#   $4 is the number of entities stored in the described section.
> +#   $5 is the offset in the DOF program of the described section.
> +#   $6 is the size of the described section, in bytes.
> +
> +f_gen_dof_sect_header()
> +{
> +    f_gen_asm ""
> +    f_gen_asm "/* dtrace_dof_sect for the $1 section.  */"
> +    f_gen_asm ".balign 8"
> +    f_gen_asm ".4byte $2\t/* uint32_t dofs_type  */"
> +    f_gen_asm ".4byte $3\t/* uint32_t dofs_align  */"
> +    # The DOF_SECF_LOAD flag is 1 => loadable section.
> +    f_gen_asm ".4byte 1\t/* uint32_t dofs_flags  */"
> +    f_gen_asm ".4byte $4\t/* uint32_t dofs_entsize  */"
> +    f_gen_asm ".8byte $5\t/* uint64_t dofs_offset  */"
> +    f_gen_asm ".8byte $6\t/* uint64_t dofs_size  */"
> +}
> +
> +# Generate a DOF program and assembly it in the output file.
> +#
> +# The DOF program generated by this function has the following
> +# structure:
> +#
> +# HEADER
> +# STRTAB OFFTAB EOFFTAB [PROBES PROVIDER]...
> +# STRTAB_SECT OFFTAB_SECT EOFFTAB_SECT ARGTAB_SECT [PROBES_SECT PROVIDER_SECT]...
> +#
> +# Input globals:
> +#   probes, base_probes, providers, probes_args, BCOUNT
> +
> +f_gen_dof_program()
> +{   
> +    ###### Variables used to cache information needed later.
> +    
> +    # Number of section headers in the generated DOF program.
> +    dof_secnum=0
> +    # Offset of section headers in the generated DOF program, in bytes.
> +    dof_secoff=0
> +
> +    # Sizes of the STRTAB, OFFTAB and EOFFTAB sections, in bytes.
> +    strtab_size=0
> +    offtab_size=0
> +    eofftab_size=0
> +    
> +    # Offsets of the STRTAB, OFFTAB EOFFTAB and PROBES sections in the
> +    # generated DOF program.  In bytes.
> +    strtab_offset=0
> +    offtab_offset=0
> +    eofftab_offset=0
> +    argtab_offset=0
> +    probes_offset=0
> +    
> +    # Indexes of the section headers of the STRTAB, OFFTAB, EOFFTAB and
> +    # PROBES sections in the sections array.
> +    strtab_sect_index=0
> +    offtab_sect_index=0
> +    eofftab_sect_index=0
> +    argtab_sect_index=0
> +    probes_sect_index=0
> +
> +    # First offsets and eoffsets of the base-probes.
> +    # Lines: PROVIDER(S) NAME(S) BASE(D) (DOF_OFFSET(D)|DOF_EOFFSET(D))
> +    probes_dof_offsets=
> +    probes_dof_eoffsets=
> +    
> +    # Offsets in the STRTAB section for the first type of base probes.
> +    # Record per line: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
> +    probes_dof_types=
> +
> +
> +    # Offsets of the provider names in the provider's STRTAB section.
> +    # Lines: PROVIDER(S) OFFSET(D)
> +    providers_dof_names=
> +
> +    # Offsets of the base-probe names in the provider's STRTAB section.
> +    # Lines: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
> +    probes_dof_names=
> +    
> +    # Offsets of the provider sections in the DOF program.
> +    # Lines: PROVIDER(S) OFFSET(D)
> +    providers_offsets=
> +
> +    ###### Generation phase.
> +    
> +    # The header of the DOF program contains a `struct
> +    # dtrace_dof_hdr'.  Record its size, but it is written at the end
> +    # of the function.
> +    f_incr_bcount $dof_hdrsize; f_align_bcount 8
> +
> +    # The STRTAB section immediately follows the header.  It contains
> +    # the following set of packed null-terminated strings:
> +    #
> +    # [PROVIDER [BASE_PROBE_NAME [BASE_PROBE_ARG_TYPE...]]...]...
> +    strtab_offset=$BCOUNT
> +    strtab_sect_index=$dof_secnum
> +    dof_secnum=$((dof_secnum + 1))
> +    f_gen_asm ""
> +    f_gen_asm "/* The STRTAB section.  */"
> +    f_gen_asm ".balign 8"
> +    # Add the provider names.
> +    off=0
> +    while read provider; do
> +        strtab_size=$(($strtab_size + ${#prov} + 1))
> +        # Note the funny mangling...
> +        f_gen_asm ".asciz \"$(printf %s $provider | $TR _ -)\""
> +        providers_dof_names=$(f_add_record "$providers_dof_names" \
> +                                           "$provider $off")
> +        off=$(($off + ${#provider} + 1))
> +
> +        # Add the base-probe names.
> +        while read p_provider name base base_sym; do
> +            test "$p_provider" = "$provider" || continue
> +            # And yes, more funny mangling...
> +            f_gen_asm ".asciz \"$(printf %s $name | $TR _ -)\""
> +            probes_dof_names=$(f_add_record "$probes_dof_names" \
> +                                            "$p_provider $name $base $off")
> +            off=$(($off + ${#name} + 1))
> +            while read args; do
> +                a_provider=$(printf %s "$args" | $CUT -d: -f1)
> +                a_name=$(printf %s "$args" | $CUT -d: -f2)
> +                test "$a_provider" = "$p_provider" \
> +                    && test "$a_name" = "$name" \
> +                    || continue
> +
> +                probes_dof_types=$(f_add_record "$probes_dof_types" \
> +                                                "$a_provider $name $base $off")
> +                nargs=$(printf %s "$args" | $CUT -d: -f3)
> +                for n in $($SEQ $nargs); do
> +                    arg=$(printf %s "$args" | $CUT -d: -f$(($n + 3)))
> +                    f_gen_asm ".asciz \"${arg}\""
> +                    off=$(($off + ${#arg} + 1))
> +                done                
> +            done <<EOF
> +$probes_args
> +EOF
> +        done <<EOF
> +$base_probes
> +EOF
> +    done <<EOF
> +$providers
> +EOF
> +    strtab_size=$off
> +    f_incr_bcount $strtab_size; f_align_bcount 8
> +
> +    # The OFFTAB section contains a set of 32bit words, one per
> +    # defined regular probe.
> +    offtab_offset=$BCOUNT
> +    offtab_sect_index=$dof_secnum
> +    dof_secnum=$((dof_secnum + 1))
> +    f_gen_asm ""
> +    f_gen_asm "/* The OFFTAB section.  */"
> +    f_gen_asm ".balign 8"
> +    off=0
> +    while read type provider name offset base base_sym; do
> +        test "$type" = "p" || continue
> +        f_gen_asm ".4byte $offset\t/* probe ${provider}:${name}  */"
> +        probes_dof_offsets=$(f_add_record "$probes_dof_offsets" \
> +                                          "$provider $name $base $off")
> +        off=$(($off + 4))
> +    done <<EOF
> +$probes
> +EOF
> +    offtab_size=$off
> +    f_incr_bcount $offtab_size; f_align_bcount 8
> +
> +    # The EOFFTAB section contains a set of 32bit words, one per
> +    # defined is-enabled probe.
> +    eofftab_offset=$BCOUNT
> +    eofftab_sect_index=$dof_secnum
> +    dof_secnum=$((dof_secnum + 1))
> +    f_gen_asm ""
> +    f_gen_asm "/* The EOFFTAB section.  */"
> +    f_gen_asm ".balign 8"
> +    off=0
> +    while read type provider name offset base base_sym; do
> +        test "$type" = "e" || continue
> +        f_gen_asm ".4byte $offset\t/* is-enabled probe ${provider}:${name}  */"
> +        probes_dof_eoffsets=$(f_add_record "$probes_dof_eoffsets" \
> +                                           "$provider $name $base $off")
> +        off=$(($off + 4))
> +    done <<EOF
> +$probes
> +EOF
> +    eofftab_size=$off
> +    f_incr_bcount $eofftab_size; f_align_bcount 8
> +
> +    # The ARGTAB section is empty, but nonetheless has a section
> +    # header, so record its section index here.
> +    argtab_offset=0
> +    argtab_sect_index=$dof_secnum
> +    dof_secnum=$((dof_secnum + 1))
> +
> +    # Generate a pair of sections PROBES and PROVIDER for each
> +    # provider.
> +    while read prov; do
> +        # The PROBES section contains an array of `struct
> +        # dtrace_dof_probe'.
> +        #
> +        # A `dtrace_dof_probe' entry characterizes the collection of
> +        # probes and is-enabled probes sharing the same provider, name and
> +        # base address.
> +        probes_sect_index=$dof_secnum
> +        dof_secnum=$((dof_secnum + 1))
> +        probes_offset=$BCOUNT        
> +        num_base_probes=$(printf %s\\n "$base_probes" | $WC -l)
> +        while read provider name base base_sym; do
> +            name_offset=$(printf %s\\n "$probes_dof_names" \
> +                          | $EGREP "^$provider $name " | $CUT -d' ' -f4)
> +
> +            num_offsets=$(printf %s\\n "$probes_dof_offsets" \
> +                          | $EGREP "^$provider $name [0-9]+ " | $WC -l)
> +            
> +            first_offset=0
> +            test "$num_offsets" -gt 0 && \
> +              first_offset=$(printf %s\\n "$probes_dof_offsets" \
> +                             | $EGREP "^$provider $name " | $CUT -d' ' -f4 | $HEAD -1)
> +
> +            num_eoffsets=$(printf %s\\n "$probes_dof_eoffsets" \
> +                           | $EGREP "^$provider $name [0-9]+ " | $WC -l)
> +            first_eoffset=0
> +            test "$num_eoffsets" -gt 0 && \
> +              first_eoffset=$(printf %s "$probes_dof_eoffsets" \
> +                              | $EGREP "^$provider $name " | $CUT -d' ' -f4 | $HEAD -1)
> +
> +            num_args=$(printf %s "$probes_args" \
> +                       | $EGREP "^$provider:$name:" | $CUT -d: -f3 | $HEAD -1)
> + 
> +            first_type=$(printf %s "$probes_dof_types" \
> +                         | $EGREP "^$provider $name $base " | $CUT -d' ' -f4 | $HEAD -1)
> +
> +            reloctype=R_X86_64_GLOB_DAT
> +            test "$objbits" = "32" && reloctype=R_386_32
> +            
> +            f_gen_asm ""
> +            f_gen_asm "/* dtrace_dof_probe for ${provider}:${name} at ${base_sym}  */"
> +            f_gen_asm ".balign 8"
> +            f_gen_asm ".reloc ., $reloctype, $base_sym + 0"
> +            f_gen_asm ".8byte ${base}\t/* uint64_t dofpr_addr  */"
> +            f_gen_asm ".4byte 0\t/* uint32_t dofpr_func  */"
> +            f_gen_asm ".4byte $name_offset\t/* uint32_t dofpr_name   */"
> +            f_gen_asm ".4byte $first_type\t/* uint32_t dofpr_nargv  */"
> +            f_gen_asm ".4byte 0\t/* uint32_t dofpr_xargv  */"
> +            f_gen_asm ".4byte 0\t/* uint32_t dofpr_argidx */"
> +            f_gen_asm ".4byte $(($first_offset/4))\t/* uint32_t dofpr_offidx  */"
> +            f_gen_asm ".byte  $num_args\t/* uint8_t dofpr_nargc  */"
> +            f_gen_asm ".byte  0\t/* uint8_t dofpr_xargc  */"
> +            f_gen_asm ".2byte $num_offsets\t/* uint16_t dofpr_noffs  */"
> +            f_gen_asm ".4byte $(($first_eoffset/4))\t/* uint32_t dofpr_enoffidx  */"
> +            f_gen_asm ".2byte $num_eoffsets\t/* uint16_t dofpr_nenoffs  */"
> +            f_gen_asm ".2byte 0\t/* uint16_t dofpr_pad1  */"
> +            f_gen_asm ".4byte 0\t/* uint16_t dofpr_pad2  */"
> +
> +            f_incr_bcount "$dof_probesize"
> +        done <<EOF
> +$base_probes
> +EOF
> +
> +        # The PROVIDER section contains a `struct dtrace_dof_provider'
> +        # instance describing the provider for the probes above.
> +        dof_secnum=$((dof_secnum + 1))
> +        providers_offsets=$(f_add_record "$providers_offsets" \
> +                                         "$prov $BCOUNT")
> +        # The dtrace_dof_provider.
> +        provider_name_offset=$(printf %s "$providers_dof_names" \
> +                                      | $EGREP "^$prov " | $CUT -d' ' -f2)
> +
> +        f_gen_asm ""
> +        f_gen_asm "/* dtrace_dof_provider for $prov  */"
> +        f_gen_asm ".balign 8"
> +        # Links to several DOF sections.
> +        f_gen_asm ".4byte $strtab_sect_index\t/* uint32_t dofpv_strtab  */"
> +        f_gen_asm ".4byte $probes_sect_index\t/* uint32_t dofpv_probes  */"
> +        f_gen_asm ".4byte $argtab_sect_index\t/* uint32_t dofpv_prargs  */"
> +        f_gen_asm ".4byte $offtab_sect_index\t/* uint32_t dofpv_proffs  */"
> +        # Offset of the provider name into the STRTAB section.
> +        f_gen_asm ".4byte $provider_name_offset\t/* uint32_t dofpv_name  */"
> +        # The rest of fields can be 0 for our modest purposes :)
> +        f_gen_asm ".4byte 0\t/* uint32_t dofpv_provattr  */"
> +        f_gen_asm ".4byte 0\t/* uint32_t dofpv_modattr  */"
> +        f_gen_asm ".4byte 0\t/* uint32_t dofpv_funcattr  */"
> +        f_gen_asm ".4byte 0\t/* uint32_t dofpv_nameattr  */"
> +        f_gen_asm ".4byte 0\t/* uint32_t dofpv_argsattr  */"
> +        # But not this one, of course...
> +        f_gen_asm ".4byte $eofftab_sect_index\t/* uint32_t dofpv_prenoffs  */"
> +
> +        f_incr_bcount $dof_providersize
> +    done<<EOF
> +$providers
> +EOF
> +    f_align_bcount 8
> +
> +    # The section headers follow, one per section defined above.
> +    dof_secoff=$BCOUNT
> +
> +    f_gen_dof_sect_header STRTAB \
> +                          $dof_sect_type_strtab \
> +                          1 1 $strtab_offset $strtab_size
> +    f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> +    f_gen_dof_sect_header OFFTAB \
> +                          $dof_sect_type_proffs \
> +                          4 4 $offtab_offset $offtab_size
> +    f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> +    f_gen_dof_sect_header EOFFTAB \
> +                          $dof_sect_type_prenoffs \
> +                          4 4 $eofftab_offset $eofftab_size
> +    f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> +    f_gen_dof_sect_header ARGTAB \
> +                          $dof_sect_type_prargs \
> +                          4 1 $argtab_offset 0
> +    f_incr_bcount $dof_secsize; f_align_bcount 8
> +    
> +    while read provider; do
> +        provider_offset=$(printf %s "$providers_offsets" \
> +                          | $EGREP "^$provider " | $CUT -d' ' -f2)
> +        num_base_probes=$(printf %s\\n "$base_probes" | $WC -l)
> +
> +        f_gen_dof_sect_header "$provider probes" \
> +                              $dof_sect_type_probes \
> +                              8 $dof_probesize $probes_offset \
> +                              $((num_base_probes * dof_probesize))
> +        f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> +        f_gen_dof_sect_header "$provider provider" \
> +                              $dof_sect_type_provider \
> +                              8 1 $provider_offset $dof_providersize
> +        f_incr_bcount $dof_secsize; f_align_bcount 8
> +    done <<EOF
> +$providers
> +EOF
> +
> +    # Finally, cook the header.
> +    asmbody="$asmprogram"
> +    asmprogram=""
> +    f_gen_asm "/* File generated by pdtrace.  */"
> +    f_gen_asm ""
> +
> +    f_gen_asm ".section .SUNW_dof,\"a\",\"progbits\""
> +    f_gen_asm ".globl __SUNW_dof"
> +    f_gen_asm ".hidden __SUNW_dof"
> +    f_gen_asm ".size __SUNW_dof, ${BCOUNT}"
> +    f_gen_asm ".type __SUNW_dof, @object"
> +    f_gen_asm "__SUNW_dof:"
> +
> +    f_gen_asm ""
> +    f_gen_asm "/* dtrace_dof_hdr */"
> +    f_gen_asm ".balign 8"
> +    f_gen_asm ".byte  0x7f, 'D, 'O, 'F\t/* dofh_ident[0..3] */"
> +    f_gen_asm ".byte  2\t\t/* model: 1=ILP32, 2=LP64 */"
> +    f_gen_asm ".byte  1\t\t/* encoding: 1: little-endian, 2: big-endian */"
> +    f_gen_asm ".byte  2\t\t/* DOF version: 1 or 2.  Latest is 2 */"
> +    f_gen_asm ".byte  2\t\t/* DIF version: 1 or 2.  Latest is 2 */"
> +    f_gen_asm ".byte  8\t\t/* number of DIF integer registers */"
> +    f_gen_asm ".byte  8\t\t/* number of DIF tuple registers */"
> +    f_gen_asm ".byte  0, 0\t\t/* dofh_ident[10..11] */"
> +    f_gen_asm ".4byte 0\t\t/* dofh_ident[12..15] */"
> +    f_gen_asm ".4byte 0\t/* uint32_t dofh_flags  */"  # See Limitations above.
> +    f_gen_asm ".4byte ${dof_hdrsize}\t/* uint32_t dofh_hdrsize  */"
> +    f_gen_asm ".4byte ${dof_secsize}\t/* uint32_t dofh_secsize */"
> +    f_gen_asm ".4byte ${dof_secnum}\t/* uint32_t dofh_secnum  */"
> +    f_gen_asm ".8byte ${dof_secoff}\t/* uint64_t dofh_secoff  */"
> +    f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_loadsz  */"
> +    f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_filesz  */"
> +    f_gen_asm ".8byte 0\t/* uint64_t dofh_pad  */"
> +    f_gen_asm ""
> +
> +    # Ok, now assembly the program in OFILE
> +    echo "$asmprogram$asmbody" | $AS -$objbits -o $ofile
> +
> +    # Next step is to change the sh_type of the ".SUNW_dof" section
> +    # headers to 0x6ffffff4 (SHT_SUNW_dof).
> +    #
> +    # Note that this code relies in the fact that readelf will list
> +    # the sections ordered in the same order than the section headers
> +    # in the section header table of the file.
> +    elfinfo=$($READELF -a $ofile)
> +
> +    # Mind the endianness.
> +    if printf %s "$elfinfo" | $EGREP -q "little endian"; then
> +        sht_sunw_dof=$(printf %s%s%s%s \\364 \\377 \\377 \\157)
> +    else
> +        sht_sunw_dof=$(printf %s%s%s%s \\157 \\377 \\377 \\364)
> +    fi
> +
> +    shdr_start=$(printf %s "$elfinfo" \
> +                | $EGREP "^[ \t]*Start of section headers:" \
> +                | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> +    test -n "$shdr_start" \
> +        || f_panic "could not extract the start of shdr from $ofile"
> +
> +    shdr_num_entries=$(printf %s "$elfinfo" \
> +                       | $EGREP "^[ \t]*Size of section headers:" \
> +                       | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> +    test -n "$shdr_num_entries" \
> +         || f_panic "could not extract the number of shdr entries from $ofile"
> +
> +    shdr_entry_size=$(printf %s "$elfinfo" \
> +                      | $EGREP "^[ \t]*Size of section headers:" \
> +                      | $SED -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> +    test -n "$shdr_entry_size" \
> +         || f_panic "could not fetch the size of section headers from $ofile"
> +
> +    while read line; do
> +        data=$(printf %s "$line" \
> +               | $SED -E -e 's/.*\[(.*)\][ \t]+([a-zA-Z_.]+).*/\1:\2/')
> +        num=$(printf %s "$data" | $CUT -d: -f1)
> +        name=$(printf %s "$data" | $CUT -d: -f2)
> +        if test "$name" = ".SUNW_dof"; then
> +            # Patch the new sh_type in the proper entry of the section
> +            # header table.
> +            printf "$sht_sunw_dof" \
> +                   | dd of=$ofile conv=notrunc count=4 ibs=1 bs=1 \
> +                        seek=$((shdr_start + (shdr_entry_size * num) + 4)) \
> +                        2> /dev/null
> +            break
> +        fi
> +    done <<EOF
> +$(printf %s "$elfinfo" | $EGREP "^[ \t]*\[[0-9 ]+\].*[A-Z]+.*PROGBITS")
> +EOF
> +
> +}
> +
> +# Patch the probed points in the given object file, replacing the
> +# function calls with NOPs.
> +#
> +# The probed points in the input object files are function calls.
> +# This function replaces these function calls by some other
> +# instruction sequences.  Which replacement to use depends on several
> +# factors, as documented below.
> +#
> +# Arguments:
> +#  $1 is the object file to patch.
> +
> +f_patch_objfile()
> +{
> +    objfile=$1
> +    
> +    # Several x86_64 instruction opcodes, in octal.
> +    x86_op_nop=$(printf \\220)
> +    x86_op_ret=$(printf \\303)
> +    x86_op_call=$(printf \\350)
> +    x86_op_jmp32=$(printf \\351)
> +    x86_op_rex_rax=$(printf \\110)
> +    x86_op_xor_eax_0=$(printf \\063)
> +    x86_op_xor_eax_1=$(printf \\300)
> +    
> +    # Figure out the file offset of the text section in the object
> +    # file.
> +    text_off=0x$(objdump -j .text -h $objfile \
> +                 | grep \.text | $TR -s ' ' | $CUT -d' ' -f 7)
> +
> +    while read type provider name offset base base_sym; do
> +        # Calculate the offset of the probed point in the object file.
> +        # Note that the `offset' of is-enabled probes is tweaked in
> +        # `f_collect_probes" to point ahead the patching point.
> +        probe_off=$((text_off + base + offset))
> +        if test "$type" = "e"; then
> +            if test "$objbits" -eq "32"; then
> +                probe_off=$((probe_off - 2))
> +            else # 64 bits
> +                probe_off=$((probe_off - 3))
> +            fi
> +        fi
> +
> +        # The probed point can be either a CALL instruction or a JMP
> +        # instruction (a tail call).  This has an impact on the
> +        # patching sequence.  Fetch the first byte at the probed point
> +        # and do the right thing.
> +        nopret="$x86_op_nop"
> +        byte=$(dd if=$objfile count=1 ibs=1 bs=1 skip=$probe_off 2> /dev/null)
> +        test "$byte" = "$x86_op_jmp32" && nopret="$x86_op_ret"
> +
> +        # Determine the patching sequence.  It depends on the type of
> +        # probe at hand (regular or is-enabled) and also if
> +        # manipulating a 32bit or 64bit binary.
> +        patchseq=
> +        case $type in
> +            p) patchseq=$(printf %s%s%s%s%s \
> +                                 "$nopret" \
> +                                 "$x86_op_nop" \
> +                                 "$x86_op_nop" \
> +                                 "$x86_op_nop" \
> +                                 "$x86_op_nop")
> +               ;;
> +            e) test "$objbits" -eq 64 && \
> +                 patchseq=$(printf %s%s%s%s%s \
> +                                   "$x86_op_rex_rax" \
> +                                   "$x86_op_xor_eax_0" \
> +                                   "$x86_op_xor_eax_1" \
> +                                   "$nopret" \
> +                                   "$x86_op_nop")
> +               test "$objbits" -eq 32 && \
> +                 patchseq=$(printf %s%s%s%s%s \
> +                                   "$x86_op_xor_eax_0" \
> +                                   "$x86_op_xor_eax_1" \
> +                                   "$nopret" \
> +                                   "$x86_op_nop" \
> +                                   "$x86_op_nop")
> +               ;;
> +            *) f_panic "internal error: wrong probe type $type";;
> +        esac
> +
> +        # Patch!
> +        printf %s "$patchseq" \
> +               | dd of=$objfile conv=notrunc count=5 ibs=1 bs=1 seek=$probe_off 2> /dev/null
> +    done <<EOF
> +$probes
> +EOF
> +    
> +    # Finally, we have to remove the __dtrace_* and __dtraceenabled_*
> +    # symbols from the object file, along with their respective
> +    # relocations.
> +    #
> +    # Note that the most obvious call:
> +    #   strip -v -N whatever -w foo.o
> +    # will not work:
> +    #   strip: not stripping symbol `whatever' because it is named in a relocation
> +    #
> +    # Fortunately using `-K !whatever' instead tricks strip to do the
> +    # right thing, but this is black magic and may eventually stop
> +    # working...
> +    $STRIP -K '!__dtrace_*' -w $objfile
> +    $STRIP -K '!__dtraceenabled_*' -w $objfile
> +}
> +
> +# Read the input .d file and print a header file with macros to
> +# invoke the probes defined in it.
> +
> +f_gen_header_file()
> +{
> +    guard=$(basename $ofile | $TR - _ | $CUT -d. -f1 | $TR a-z A-Z)
> +    printf "/*\n * Generated by pdtrace.\n */\n\n"
> +
> +    printf "#ifndef _${guard}_H\n"
> +    printf "#define _${guard}_H\n\n"
> +
> +    printf "#include <unistd.h>\n"
> +    printf "#include <inttypes.h>\n"
> +    printf \\n\\n
> +
> +    printf "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"
> +
> +    printf "#define _DTRACE_VERSION 1\n\n"
> +
> +    provider=$(cat $dfile | $EGREP "^ *provider +([a-zA-Z_]+)" \
> +               | $SED -E -e 's/^ *provider +([a-zA-Z]+).*/\1/')
> +    test -z "$provider" \
> +        && f_panic "unable to parse the provider name from $dfile."
> +    u_provider=$(printf %s "$provider" | $TR a-z A-Z | $TR -s _)
> +    
> +    cat $dfile | $EGREP "^ *probe +[a-zA-Z_]+ *\(.*\);" | \
> +        while read line; do
> +            # Extract the probe name.
> +            name=$(printf %s "$line" \
> +                   | $SED -E -e 's/^ *probe +([a-zA-Z_]+).*/\1/')
> +            u_name=$(printf %s "$name" | $TR a-z A-Z | $TR -s _)
> +
> +            # Generate an arg1,arg2,...,argN line for the probe.
> +            args=""; nargs=0; aline=$(printf %s "$line" | $SED -e 's/.*(\(.*\)).*/\1/')
> +            set -f; IFS=,
> +            for arg in $aline; do
> +                args="${args}arg${nargs},"
> +                nargs=$((nargs + 1))
> +            done
> +            set +f; unset IFS
> +            args=${args%,}
> +
> +            echo "#if _DTRACE_VERSION"
> +            echo ""
> +            
> +            # Emit the macros for the probe.
> +            echo "#define ${u_provider}_${u_name}($args) \\"
> +            echo "   __dtrace_${provider}___${name}($args)"
> +            echo "#define ${u_provider}_${u_name}_ENABLED() \\"
> +            echo "   __dtraceenabled_${provider}___${name}()"
> +
> +            # Emit the extern definitions for the probe dummy
> +            # functions.
> +            echo ""
> +            printf %s\\n "$line" \
> +                | $SED -E -e "s/^ *probe +/extern void __dtrace_${provider}___/"
> +            echo "extern int __dtraceenabled_${provider}___${name}(void);"
> +
> +
> +            printf "\n#else\n"
> +
> +            # Emit empty macros for the probe
> +            echo "#define ${u_provider}_${u_name}($args)"
> +            echo "#define ${u_provider}_${u_name}_ENABLED() (0)"
> +
> +            printf "\n#endif /* _DTRACE_VERSION */\n"
> +        done
> +
> +    printf "#ifdef __cplusplus\n}\n#endif\n\n"
> +    printf "#endif /* _${guard}_H */\n"
> +}
> +
> +### Main program.
> +
> +# Process command line arguments.
> +
> +test "$#" -eq "0" && f_usage
> +
> +genelf=0
> +genheader=0
> +objbits=64
> +ofile=
> +dfile=
> +while getopts VG3264hs:o: name; do
> +    case $name in
> +        V) f_version;;
> +        s) dfile="$OPTARG";
> +           test -f "$dfile" || f_panic "cannot read $dfile";;
> +        o) ofile="$OPTARG";;
> +        G) genelf=1;;
> +        h) genheader=1;;
> +        # Note the trick to support -32
> +        3) objbits=666;;
> +        2) test "$objbits" -eq 666 || f_usage; objbits=32;;
> +        # Likewise for -64
> +        6) objbits=777;;
> +        4) test "$objbits" -eq 777 || f_usage; objbits=64;;
> +        ?) f_usage;;
> +    esac
> +done
> +shift $(($OPTIND - 1))
> +
> +test "$objbits" -eq "32" || test "$objbits" -eq "64" \
> +    || f_usage
> +
> +test $((genelf + genheader)) -gt 1 && \
> +    { echo "Please use either -G or -h."; f_usage; }
> +
> +test -n "$dfile" || { echo "Please specify a .d file with -s."; exit 2; }
> +
> +if test "$genelf" -gt 0; then
> +    # In this mode there must be a remaining argument: the name of the
> +    # object file to inspect for probed points.
> +    test "$#" -ne "1" && f_usage
> +    test -f "$1" || f_panic "cannot read $1"
> +    objfile=$1
> +
> +    # Collect probe information from the input object file and the
> +    # d-script.
> +    f_collect_probes $objfile    
> +    f_collect_probes_args $dfile
> +
> +    # Generate the assembly code and assemble the DOF program in
> +    # OFILE.  Then patch OBJFILE to remove the dummy probe calls.
> +    f_gen_dof_program
> +    f_patch_objfile $objfile
> +fi
> +
> +if test "$genheader" -gt 0; then
> +    test -n "$ofile" || { echo "Please specify an output file with -o."; exit 2; }
> +    
> +    # In this mode no extra arguments shall be present.
> +    test "$#" -ne "0" && f_usage
> +
> +    f_gen_header_file > $ofile
> +fi
> +
> +# pdtrace ends here.
> -- 
> 1.7.10.4

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 3/9] New commands `enable probe' and `disable probe'.
  2015-02-02 10:57 ` [PATCH V4 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
  2015-02-02 16:01   ` Eli Zaretskii
@ 2015-02-17  1:54   ` Sergio Durigan Junior
  1 sibling, 0 replies; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:54 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> This patch adds the above-mentioned commands to the generic probe
> abstraction implemented in probe.[ch].  The effects associated to
> enabling or disabling a probe depend on the type of probe being
> handled, and is triggered by invoking two back-end hooks in
> `probe_ops'.
>
> In case some particular probe type does not support the notion of
> enabling and/or disabling, the corresponding fields on `probe_ops' can
> be initialized to NULL.  This is the case of SystemTap probes.

Thanks for the patch.  I see you addressed all the comments that I
made in the previous cycle.  I have no further comments.  OK.

> gdb/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* stap-probe.c (stap_probe_ops): Add NULLs in the static
> 	stap_probe_ops for `enable_probe' and `disable_probe'.
> 	* probe.c (enable_probes_command): New function.
> 	(disable_probes_command): Likewise.
> 	(_initialize_probe): Define the cli commands `enable probe' and
> 	`disable probe'.
> 	(parse_probe_linespec): New function.
> 	(info_probes_for_ops): Use parse_probe_linespec.
> 	* probe.h (probe_ops): New hooks `enable_probe' and
> 	`disable_probe'.
>
> gdb/doc/ChangeLog:
>
> 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
>
> 	* gdb.texinfo (Static Probe Points): Cover the `enable probe' and
> 	`disable probe' commands.
> ---
>  gdb/ChangeLog       |   13 +++++
>  gdb/doc/ChangeLog   |    5 ++
>  gdb/doc/gdb.texinfo |   29 ++++++++++
>  gdb/probe.c         |  153 +++++++++++++++++++++++++++++++++++++++++++++------
>  gdb/probe.h         |   12 ++++
>  gdb/stap-probe.c    |    2 +
>  6 files changed, 198 insertions(+), 16 deletions(-)
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index aee17d3..4ab0bba 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -5011,6 +5011,35 @@ given, all object files are considered.
>  List the available static probes, from all types.
>  @end table
>  
> +@cindex enabling and disabling probes
> +Some probe points can be enabled and/or disabled.  The effect of
> +enabling or disabling a probe depends on the type of probe being
> +handled.  @code{SystemTap} probes cannot be disabled.
> +
> +You can enable (or disable) one or more probes using the following
> +commands, with optional arguments:
> +
> +@table @code
> +@kindex enable probes
> +@item enable probes @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 enable.  If omitted,
> +all probes from all providers are enabled.
> +
> +If given, @var{name} is a regular expression to match against probe
> +names when selecting which probes to enable.  If omitted, probe names
> +are not considered when deciding whether to enable 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.
> +
> +@kindex disable probes
> +@item disable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
> +See the @code{enable probes} command above for a description of the
> +optional arguments accepted by this command.
> +@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
> diff --git a/gdb/probe.c b/gdb/probe.c
> index 98113eb..741c120 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -527,6 +527,24 @@ exists_probe_with_pops (VEC (bound_probe_s) *probes,
>    return 0;
>  }
>  
> +/* Helper function that parses a probe linespec of the form [PROVIDER
> +   [PROBE [OBJNAME]]] from the provided string STR.  */
> +
> +static void
> +parse_probe_linespec (const char *str, char **provider,
> +		      char **probe_name, char **objname)
> +{
> +  *probe_name = *objname = NULL;
> +
> +  *provider = extract_arg_const (&str);
> +  if (*provider != NULL)
> +    {
> +      *probe_name = extract_arg_const (&str);
> +      if (*probe_name != NULL)
> +	*objname = extract_arg_const (&str);
> +    }
> +}
> +
>  /* See comment in probe.h.  */
>  
>  void
> @@ -546,22 +564,10 @@ info_probes_for_ops (const char *arg, int from_tty,
>    struct bound_probe *probe;
>    struct gdbarch *gdbarch = get_current_arch ();
>  
> -  /* Do we have a `provider:probe:objfile' style of linespec?  */
> -  provider = extract_arg_const (&arg);
> -  if (provider)
> -    {
> -      make_cleanup (xfree, provider);
> -
> -      probe_name = extract_arg_const (&arg);
> -      if (probe_name)
> -	{
> -	  make_cleanup (xfree, probe_name);
> -
> -	  objname = extract_arg_const (&arg);
> -	  if (objname)
> -	    make_cleanup (xfree, objname);
> -	}
> -    }
> +  parse_probe_linespec (arg, &provider, &probe_name, &objname);
> +  make_cleanup (xfree, provider);
> +  make_cleanup (xfree, probe_name);
> +  make_cleanup (xfree, objname);
>  
>    probes = collect_probes (objname, provider, probe_name, pops);
>    make_cleanup (VEC_cleanup (probe_p), &probes);
> @@ -689,6 +695,98 @@ info_probes_command (char *arg, int from_tty)
>    info_probes_for_ops (arg, from_tty, NULL);
>  }
>  
> +/* Implementation of the `enable probes' command.  */
> +
> +static void
> +enable_probes_command (char *arg, int from_tty)
> +{
> +  char *provider, *probe_name = NULL, *objname = NULL;
> +  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
> +  VEC (bound_probe_s) *probes;
> +  struct bound_probe *probe;
> +  int i;
> +
> +  parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
> +  make_cleanup (xfree, provider);
> +  make_cleanup (xfree, probe_name);
> +  make_cleanup (xfree, objname);
> +
> +  probes = collect_probes (objname, provider, probe_name, NULL);
> +  if (VEC_empty (bound_probe_s, probes))
> +    {
> +      ui_out_message (current_uiout, 0, _("No probes matched.\n"));
> +      do_cleanups (cleanup);
> +      return;
> +    }
> +
> +  /* Enable the selected probes, provided their backends support the
> +     notion of enabling a probe.  */
> +  for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> +    {
> +      const struct probe_ops *pops = probe->probe->pops;
> +
> +      if (pops->enable_probe != NULL)
> +	{
> +	  pops->enable_probe (probe->probe);
> +	  ui_out_message (current_uiout, 0,
> +			  _("Probe %s:%s enabled.\n"),
> +			  probe->probe->provider, probe->probe->name);
> +	}
> +      else
> +	ui_out_message (current_uiout, 0,
> +			_("Probe %s:%s cannot be enabled.\n"),
> +			probe->probe->provider, probe->probe->name);
> +    }
> +
> +  do_cleanups (cleanup);
> +}
> +
> +/* Implementation of the `disable probes' command.  */
> +
> +static void
> +disable_probes_command (char *arg, int from_tty)
> +{
> +  char *provider, *probe_name = NULL, *objname = NULL;
> +  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
> +  VEC (bound_probe_s) *probes;
> +  struct bound_probe *probe;
> +  int i;
> +
> +  parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
> +  make_cleanup (xfree, provider);
> +  make_cleanup (xfree, probe_name);
> +  make_cleanup (xfree, objname);
> +
> +  probes = collect_probes (objname, provider, probe_name, NULL /* pops */);
> +  if (VEC_empty (bound_probe_s, probes))
> +    {
> +      ui_out_message (current_uiout, 0, _("No probes matched.\n"));
> +      do_cleanups (cleanup);
> +      return;
> +    }
> +
> +  /* Disable the selected probes, provided their backends support the
> +     notion of enabling a probe.  */
> +  for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> +    {
> +      const struct probe_ops *pops = probe->probe->pops;
> +
> +      if (pops->disable_probe != NULL)
> +	{
> +	  pops->disable_probe (probe->probe);
> +	  ui_out_message (current_uiout, 0,
> +			  _("Probe %s:%s disabled.\n"),
> +			  probe->probe->provider, probe->probe->name);
> +	}
> +      else
> +	ui_out_message (current_uiout, 0,
> +			_("Probe %s:%s cannot be disabled.\n"),
> +			probe->probe->provider, probe->probe->name);
> +    }
> +
> +  do_cleanups (cleanup);
> +}
> +
>  /* See comments in probe.h.  */
>  
>  CORE_ADDR
> @@ -950,4 +1048,27 @@ _initialize_probe (void)
>  	   _("\
>  Show information about all type of probes."),
>  	   info_probes_cmdlist_get ());
> +
> +  add_cmd ("probes", class_breakpoint, enable_probes_command, _("\
> +Enable probes.\n\
> +Usage: enable probes [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name.\n\
> +If you do not specify any argument then the command will enable\n\
> +all defined probes."),
> +	   &enablelist);
> +
> +  add_cmd ("probes", class_breakpoint, disable_probes_command, _("\
> +Disable probes.\n\
> +Usage: disable probes [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name.\n\
> +If you do not specify any argument then the command will disable\n\
> +all defined probes."),
> +	   &disablelist);
> +
>  }
> diff --git a/gdb/probe.h b/gdb/probe.h
> index 5df1976..e8d5dfe 100644
> --- a/gdb/probe.h
> +++ b/gdb/probe.h
> @@ -138,6 +138,18 @@ struct probe_ops
>  
>      void (*gen_info_probes_table_values) (struct probe *probe,
>  					  VEC (const_char_ptr) **values);
> +
> +    /* Enable a probe.  The semantics of "enabling" a probe depend on
> +       the specific backend and the field can be NULL in case enabling
> +       probes is not supported.  */
> +
> +    void (*enable_probe) (struct probe *probe);
> +
> +    /* Disable a probe.  The semantics of "disabling" a probe depend
> +       on the specific backend and the field can be NULL in case
> +       disabling probes is not supported.  */
> +
> +    void (*disable_probe) (struct probe *probe);
>    };
>  
>  /* Definition of a vector of probe_ops.  */
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index e898f7e..eaf07b9 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1684,6 +1684,8 @@ static const struct probe_ops stap_probe_ops =
>    stap_type_name,
>    stap_gen_info_probes_table_header,
>    stap_gen_info_probes_table_values,
> +  NULL,  /* enable_probe  */
> +  NULL   /* disable_probe  */
>  };
>  
>  /* Implementation of the `info probes stap' command.  */
> -- 
> 1.7.10.4

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 0/9] Add support for DTrace USDT probes to gdb
  2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
                   ` (9 preceding siblings ...)
  2015-02-16 13:20 ` [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
@ 2015-02-17  1:57 ` Sergio Durigan Junior
  2015-02-17 11:56   ` Jose E. Marchesi
  10 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:57 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches

On Monday, February 02 2015, Jose E. Marchesi wrote:

> [Changes from V3:
> - Added some missing spaces after periods in the documentation patch.
>   Spotted by Eli.
> - Sort ChangeLog entries so they reflect the changes in the same order
>   than the diffs.
> - Use transformed tool names in the pdtrace script, which is now
>   processed through configure.  Introduce a new GDB_AC_TRANSFORM macro
>   to avoid repeating a code idiom and use it to define both
>   GDB_TRANSFORM_NAME and GCORE_TRANSFORM_NAME in the main
>   configure.ac.
> - Copyright year updated to 2015 in new files introduces by the patch
>   series.]

Thanks for the series, Jose!

The patches look pretty good.  I approved almost all of them.  The only
exception is the testcase patch, but not because of the testcase per se:
rather, it is because the new transform.m4 file that you added.  I think
we're 99% done on this.  Let's just wait to see what Pedro thinks about
the transform thing (since he was the one who requested it before).

I'm looking forward to seeing this series pushed.  Nice work!

Cheers,

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 7/9] Simple testsuite for DTrace USDT probes.
  2015-02-17  1:53   ` Sergio Durigan Junior
@ 2015-02-17  1:58     ` Sergio Durigan Junior
  2015-02-17 11:32       ` Pedro Alves
  0 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-02-17  1:58 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: gdb-patches, Pedro Alves

On Monday, February 16 2015, I wrote:

> On Monday, February 02 2015, Jose E. Marchesi wrote:
>
>> This patch adds some simple tests testing the support for DTrace USDT
>> probes.  The testsuite will be skipped as unsupported in case the user
>> does not have DTrace installed on her system.  The tests included in the
>> test suite test breakpointing on DTrace probes, enabling and disabling
>> probes, printing of probe arguments of several types and also
>> breakpointing on several probes with the same name.
>
> Thanks again for this awesome testcase.  I don't have any more comments
> to make about the patch itself; I personally liked your way of solving
> the transform problem, though I have a preference to see those changes
> in a different patch (i.e., not in the DTrace series).  Do you think you
> can do that?  It should be really easy to extract this part from your
> patch; and then, you'd only have to worry about the dtrace-side of it.
>
> I can't give you an approval for the transform.m4 thing, but for the
> rest, you have an OK.

I forgot to add Pedro in the loop.  Pedro, do you have any comments
about this?

Thanks,

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 7/9] Simple testsuite for DTrace USDT probes.
  2015-02-17  1:58     ` Sergio Durigan Junior
@ 2015-02-17 11:32       ` Pedro Alves
  0 siblings, 0 replies; 51+ messages in thread
From: Pedro Alves @ 2015-02-17 11:32 UTC (permalink / raw)
  To: Sergio Durigan Junior, Jose E. Marchesi; +Cc: gdb-patches

On 02/17/2015 01:58 AM, Sergio Durigan Junior wrote:
> On Monday, February 16 2015, I wrote:
> 
>> On Monday, February 02 2015, Jose E. Marchesi wrote:
>>
>>> This patch adds some simple tests testing the support for DTrace USDT
>>> probes.  The testsuite will be skipped as unsupported in case the user
>>> does not have DTrace installed on her system.  The tests included in the
>>> test suite test breakpointing on DTrace probes, enabling and disabling
>>> probes, printing of probe arguments of several types and also
>>> breakpointing on several probes with the same name.
>>
>> Thanks again for this awesome testcase.  I don't have any more comments
>> to make about the patch itself; I personally liked your way of solving
>> the transform problem, though I have a preference to see those changes
>> in a different patch (i.e., not in the DTrace series).  Do you think you
>> can do that?  It should be really easy to extract this part from your
>> patch; and then, you'd only have to worry about the dtrace-side of it.
>>

If we don't do that, we'd need to duplicate the transform logic in
testsuite/configure.ac.  It's fine with me to add transform.m4 now, avoiding
the duplication.

>> I can't give you an approval for the transform.m4 thing, but for the
>> rest, you have an OK.
> 
> I forgot to add Pedro in the loop.  Pedro, do you have any comments
> about this?

It looks good to me as is.

Thanks,
Pedro Alves

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

* Re: [PATCH V4 0/9] Add support for DTrace USDT probes to gdb
  2015-02-17  1:57 ` Sergio Durigan Junior
@ 2015-02-17 11:56   ` Jose E. Marchesi
  0 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-02-17 11:56 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: gdb-patches


    
    > [Changes from V3:
    > - Added some missing spaces after periods in the documentation patch.
    >   Spotted by Eli.
    > - Sort ChangeLog entries so they reflect the changes in the same order
    >   than the diffs.
    > - Use transformed tool names in the pdtrace script, which is now
    >   processed through configure.  Introduce a new GDB_AC_TRANSFORM macro
    >   to avoid repeating a code idiom and use it to define both
    >   GDB_TRANSFORM_NAME and GCORE_TRANSFORM_NAME in the main
    >   configure.ac.
    > - Copyright year updated to 2015 in new files introduces by the patch
    >   series.]
    
    Thanks for the series, Jose!
    
    The patches look pretty good.  I approved almost all of them.  The only
    exception is the testcase patch, but not because of the testcase per se:
    rather, it is because the new transform.m4 file that you added.  I think
    we're 99% done on this.  Let's just wait to see what Pedro thinks about
    the transform thing (since he was the one who requested it before).
    
Thanks.  I will remove the GDB_AC_TRANSFORM M4 macro from [PATCH V4 7/9]
and make it use verbose idioms in gdb/testsuite/configure.ac:

STRIP_TRANSFORM_NAME=`echo strip | sed -e "$transform"`
if test "x$STRIP_TRANSFORM_NAME" = x; then
   STRIP_TRANSFORM_NAME=strip
fi
[... same for readelf, as and nm]

And then I will push the patches to trunk.

Later I will send a separated patch with the addition of
GDB_AC_TRANSFORM for Pedro's consideration.

Salud!

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-02-17  1:35   ` Sergio Durigan Junior
@ 2015-03-25 19:14     ` Joel Brobecker
  2015-03-26 16:15       ` Jose E. Marchesi
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-25 19:14 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: Jose E. Marchesi, gdb-patches

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

Jose,

> > 2015-02-02  Jose E. Marchesi  <jose.marchesi@oracle.com>
> >
> > 	* breakpoint.c (BREAK_ARGS_HELP): help string updated to mention
> > 	the -probe-dtrace new vpossible value for PROBE_MODIFIER.
> > 	* configure.ac (CONFIG_OBS): dtrace-probe.o added if BFD can
> > 	handle ELF files.
> > 	* Makefile.in (SFILES): dtrace-probe.c added.
> > 	* configure: Regenerate.
> > 	* dtrace-probe.c: New file.
> > 	(SHT_SUNW_dof): New constant.
> > 	(dtrace_probe_type): New enum.
> > 	(dtrace_probe_arg): New struct.
> > 	(dtrace_probe_arg_s): New typedef.
> > 	(struct dtrace_probe_enabler): New struct.
> > 	(dtrace_probe_enabler_s): New typedef.
> > 	(dtrace_probe): New struct.
> > 	(dtrace_probe_is_linespec): New function.
> > 	(dtrace_dof_sect_type): New enum.
> > 	(dtrace_dof_dofh_ident): Likewise.
> > 	(dtrace_dof_encoding): Likewise.
> > 	(DTRACE_DOF_ENCODE_LSB): Likewise.
> > 	(DTRACE_DOF_ENCODE_MSB): Likewise.
> > 	(dtrace_dof_hdr): New struct.
> > 	(dtrace_dof_sect): Likewise.
> > 	(dtrace_dof_provider): Likewise.
> > 	(dtrace_dof_probe): Likewise.
> > 	(DOF_UINT): New macro.
> > 	(DTRACE_DOF_PTR): Likewise.
> > 	(DTRACE_DOF_SECT): Likewise.
> > 	(dtrace_process_dof_probe): New function.
> > 	(dtrace_process_dof): Likewise.
> > 	(dtrace_build_arg_exprs): Likewise.
> > 	(dtrace_get_arg): Likewise.
> > 	(dtrace_get_probes): Likewise.
> > 	(dtrace_get_probe_argument_count): Likewise.
> > 	(dtrace_can_evaluate_probe_arguments): Likewise.
> > 	(dtrace_evaluate_probe_argument): Likewise.
> > 	(dtrace_compile_to_ax): Likewise.
> > 	(dtrace_probe_destroy): Likewise.
> > 	(dtrace_gen_info_probes_table_header): Likewise.
> > 	(dtrace_gen_info_probes_table_values): Likewise.
> > 	(dtrace_probe_is_enabled): Likewise.
> > 	(dtrace_probe_ops): New variable.
> > 	(info_probes_dtrace_command): New function.
> > 	(_initialize_dtrace_probe): Likewise.
> > 	(dtrace_type_name): Likewise.

Unfortunately, this patch is breaking GDB completely on Solaris.
The first issue I started investigating is the following, which
happens with nearly any unthreaded program:

    (gdb) start
    Temporary breakpoint 1 at 0x80593bc: file simple_main.adb, line 4.
    Starting program: /[...]/simple_main 
    [Thread debugging using libthread_db enabled]
    No definition of "mutex_t" in current context.

The error happens in...

> > +static void
> > +dtrace_process_dof_probe (struct objfile *objfile,

... and more precisely...

> > +      /* Store argument type descriptions.  A description of the type
> > +         of the argument is in the (J+1)th null-terminated string
> > +         starting at 'strtab' + 'probe->dofpr_nargv'.  */
> > +      ret->args = NULL;
> > +      p = strtab + DOF_UINT (dof, probe->dofpr_nargv);
> > +      for (j = 0; j < ret->probe_argc; j++)
> > +	{
> > +	  struct dtrace_probe_arg arg;
> > +	  struct expression *expr;
> > +
> > +	  arg.type_str = xstrdup (p);
> > +
> > +	  /* Use strtab_size as a sentinel.  */
> > +	  while (*p++ != '\0' && p - strtab < strtab_size);
> > +
> > +	  /* Try to parse a type expression from the type string.  If
> > +	     this does not work then we set the type to `long
> > +	     int'.  */
> > +          arg.type = builtin_type (gdbarch)->builtin_long;
> > +	  expr = parse_expression (arg.type_str);
                 ^^^^^^^^^^^^^^^^
                 there

The most obvious issue is that type "mutex_t" does not exist in
my program, so I think that the code should handle that case.

The second, less obvious issue, is that the parsing is done using
the current language, which I don't think is a good idea. Attached
is small prototype that attempts to do something like that.
I think we need a function that parses an expression using
a specific language, but I went for short prototype to test
my theory first.

That solves most of the issues, even if I don't really know if
it's not just sweeping them under the carpet instead.

And once I had that fixed, the next issue that I looked at was:

    (gdb) b adainit
    Breakpoint 1 at 0x8051f03
    (gdb) run
    Starting program: /[...]/a
    [Thread debugging using libthread_db enabled]
    zsh: 12378 segmentation fault (core dumped)  /[...]/gdb -q a

This is where I'm getting even more out of my league, here.
The SEGV happens on the following line:

377           uint32_t enabler_offset
378             = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];

... and eofftab seems to have a bogus value, because:

    (gdb) p eofftab
    $6 = 0x9479fb2 <error: Cannot access memory at address 0x9479fb2>

For me to investigate further, I think I'd have to investigate how
probes work and what's where, and I don't really have the time or
interest at the moment. So, I'm hoping that you have access to some
Solaris systems and you could look into this?

I can send you reproducers, if you need. I investigated the issue on
x86-solaris 2.10, but the same happens on sparc-solaris 2.10 and
sparc64-solaris 2.10.

Thank you,
-- 
Joel

[-- Attachment #2: dtrace.diff --]
[-- Type: text/x-diff, Size: 1261 bytes --]

diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 491d853..5d5c5b2 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -414,6 +414,7 @@ dtrace_process_dof_probe (struct objfile *objfile,
 	{
 	  struct dtrace_probe_arg arg;
 	  struct expression *expr;
+	  struct cleanup *old_chain = NULL;
 
 	  /* Set arg.expr to ensure all fields in expr are initialized and
 	     the compiler will not warn when arg is used.  */
@@ -427,8 +428,24 @@ dtrace_process_dof_probe (struct objfile *objfile,
 	     this does not work then we set the type to `long
 	     int'.  */
           arg.type = builtin_type (gdbarch)->builtin_long;
-	  expr = parse_expression (arg.type_str);
-	  if (expr->elts[0].opcode == OP_TYPE)
+
+	  if (current_language->la_language != language_c)
+	    {
+	      old_chain = make_cleanup_restore_current_language ();
+	      set_language (language_c);
+	    }
+	  TRY
+	    {
+	      expr = parse_expression (arg.type_str);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      expr = NULL;
+	    }
+	  END_CATCH
+	  if (old_chain != NULL)
+	    do_cleanups (old_chain);
+	  if (expr != NULL && expr->elts[0].opcode == OP_TYPE)
 	    arg.type = expr->elts[1].type;
 
 	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-25 19:14     ` Joel Brobecker
@ 2015-03-26 16:15       ` Jose E. Marchesi
  2015-03-26 17:50         ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-03-26 16:15 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches


Hi Joel!
    
    > > +	  /* Try to parse a type expression from the type string.  If
    > > +	     this does not work then we set the type to `long
    > > +	     int'.  */
    > > +          arg.type = builtin_type (gdbarch)->builtin_long;
    > > +	  expr = parse_expression (arg.type_str);
                     ^^^^^^^^^^^^^^^^
                     there
    
    The most obvious issue is that type "mutex_t" does not exist in
    my program, so I think that the code should handle that case.

Certainly.
    
    The second, less obvious issue, is that the parsing is done using
    the current language, which I don't think is a good idea. Attached
    is small prototype that attempts to do something like that.
    I think we need a function that parses an expression using
    a specific language, but I went for short prototype to test
    my theory first.

    That solves most of the issues, even if I don't really know if
    it's not just sweeping them under the carpet instead.

Well, the TRY..CATCH in your prototype would catch any error that may be
thrown in parse_expression, and the `set_language' must take care of
changing the language, so I would say that is enough...
    
    And once I had that fixed, the next issue that I looked at was:
    
        (gdb) b adainit
        Breakpoint 1 at 0x8051f03
        (gdb) run
        Starting program: /[...]/a
        [Thread debugging using libthread_db enabled]
        zsh: 12378 segmentation fault (core dumped)  /[...]/gdb -q a
    
    This is where I'm getting even more out of my league, here.
    The SEGV happens on the following line:
    
    377           uint32_t enabler_offset
    378             = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];

I will debug that SIGSEGV in solaris, but the problem seems to be
related to the DOF program embedded in your program, more than to the
platform.

Could you please send me your sparc-solaris reproducer?
Salud!

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 16:15       ` Jose E. Marchesi
@ 2015-03-26 17:50         ` Joel Brobecker
  2015-03-26 18:43           ` Joel Brobecker
                             ` (2 more replies)
  0 siblings, 3 replies; 51+ messages in thread
From: Joel Brobecker @ 2015-03-26 17:50 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Sergio Durigan Junior, gdb-patches

> Well, the TRY..CATCH in your prototype would catch any error that may be
> thrown in parse_expression, and the `set_language' must take care of
> changing the language, so I would say that is enough...

OK - I will send an updated patch that makes things a little cleaner.
I didn't know whether it was OK to default to type long makes much
sense when the probe says the parameter should be using type "mutex_t".

>     And once I had that fixed, the next issue that I looked at was:
>     
>         (gdb) b adainit
>         Breakpoint 1 at 0x8051f03
>         (gdb) run
>         Starting program: /[...]/a
>         [Thread debugging using libthread_db enabled]
>         zsh: 12378 segmentation fault (core dumped)  /[...]/gdb -q a
>     
>     This is where I'm getting even more out of my league, here.
>     The SEGV happens on the following line:
>     
>     377           uint32_t enabler_offset
>     378             = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
> 
> I will debug that SIGSEGV in solaris, but the problem seems to be
> related to the DOF program embedded in your program, more than to the
> platform.
> 
> Could you please send me your sparc-solaris reproducer?

Thanks for the offer to help! Sadly, the SEGV doesn't seem to
happen on sparc-solaris, it seems. Once I apply the patch above,
I pretty much get normal results back (yay!).

So, the problem appears to be specific to x86-solaris. I didn't know
the DOF program was embedded in the executable, but I suspect there is
a problem in its contents. How do you think we should proceed?

Thanks!
-- 
Joel

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 17:50         ` Joel Brobecker
@ 2015-03-26 18:43           ` Joel Brobecker
  2015-03-26 18:53             ` Sergio Durigan Junior
  2015-03-26 23:39           ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
  2015-03-31 17:29           ` Jose E. Marchesi
  2 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-26 18:43 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Sergio Durigan Junior, gdb-patches

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

[Sergio - a change in dtrace-probe.c needs your approval, I think.
Also, if you have a chance to double-check the rest of the patch,
that'd be a much appreciated second pair of eyes!]

> > Well, the TRY..CATCH in your prototype would catch any error that may be
> > thrown in parse_expression, and the `set_language' must take care of
> > changing the language, so I would say that is enough...
> 
> OK - I will send an updated patch that makes things a little cleaner.
> I didn't know whether it was OK to default to type long makes much
> sense when the probe says the parameter should be using type "mutex_t".

Here it is.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Contain any
        exception raised while parsing the probe arguments.
        Force parsing to be done using the C language parser.
        * expression.h (parse_expression_with_language): Declare.
        * parse.c (parse_expression_with_language): New function.

Tested on sparc-solaris.

-- 
Joel

[-- Attachment #2: 0001-dtrace-probe-Handle-error-while-parsing-probe-argume.patch --]
[-- Type: text/x-diff, Size: 3496 bytes --]

From ba8991270e994cd96f92316932f65f96e47bf329 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Thu, 26 Mar 2015 19:14:03 +0100
Subject: [PATCH] dtrace-probe: Handle error while parsing probe argument.

The debugger on Solaris has been broken since the introduction of
DTrace probe support:

    (gdb) start
    Temporary breakpoint 1 at 0x80593bc: file simple_main.adb, line 4.
    Starting program: /[...]/simple_main
    [Thread debugging using libthread_db enabled]
    No definition of "mutex_t" in current context.

The problem occurs while trying to parse a probe's arguument,
and the exception propagates all the way to the top. This patch
fixes the issue by containing the exception and falling back on
using the "long" builtin type if the argument's type could not
be determined.

Also, the parsing should be done using the C language parser.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Contain any
        exception raised while parsing the probe arguments.
        Force parsing to be done using the C language parser.
        * expression.h (parse_expression_with_language): Declare.
        * parse.c (parse_expression_with_language): New function.
---
 gdb/dtrace-probe.c |   14 ++++++++++++--
 gdb/expression.h   |    3 +++
 gdb/parse.c        |   22 ++++++++++++++++++++++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 491d853..ff7ce7d 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -427,8 +427,18 @@ dtrace_process_dof_probe (struct objfile *objfile,
 	     this does not work then we set the type to `long
 	     int'.  */
           arg.type = builtin_type (gdbarch)->builtin_long;
-	  expr = parse_expression (arg.type_str);
-	  if (expr->elts[0].opcode == OP_TYPE)
+
+	  TRY
+	    {
+	      expr = parse_expression_with_language (arg.type_str, language_c);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      expr = NULL;
+	    }
+	  END_CATCH
+
+	  if (expr != NULL && expr->elts[0].opcode == OP_TYPE)
 	    arg.type = expr->elts[1].type;
 
 	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
diff --git a/gdb/expression.h b/gdb/expression.h
index f5cd0e5..d08ce05 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -97,6 +97,9 @@ struct expression
 
 extern struct expression *parse_expression (const char *);
 
+extern struct expression *parse_expression_with_language (const char *string,
+							  enum language lang);
+
 extern struct expression *parse_expression_in_context (const char *, int);
 
 extern struct type *parse_field_expression (char *, char **);
diff --git a/gdb/parse.c b/gdb/parse.c
index 2ffe52e..bc95cf1 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -1268,6 +1268,28 @@ parse_expression (const char *string)
   return exp;
 }
 
+/* Same as parse_expression, but using the given language (LANG)
+   to parse the expression.  */
+
+struct expression *
+parse_expression_with_language (const char *string, enum language lang)
+{
+  struct cleanup *old_chain = NULL;
+  struct expression *expr;
+
+  if (current_language->la_language != language_c)
+    {
+      old_chain = make_cleanup_restore_current_language ();
+      set_language (language_c);
+    }
+
+  expr = parse_expression (string);
+
+  if (old_chain != NULL)
+    do_cleanups (old_chain);
+  return expr;
+}
+
 /* As for parse_expression, except that if VOID_CONTEXT_P, then
    no value is expected from the expression.  */
 
-- 
1.7.10.4


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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 18:43           ` Joel Brobecker
@ 2015-03-26 18:53             ` Sergio Durigan Junior
  2015-03-26 21:00               ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-03-26 18:53 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jose E. Marchesi, gdb-patches

On Thursday, March 26 2015, Joel Brobecker wrote:

> [Sergio - a change in dtrace-probe.c needs your approval, I think.
> Also, if you have a chance to double-check the rest of the patch,
> that'd be a much appreciated second pair of eyes!]

Thanks, Joel.  I saw the messages yesterday but did not get a chance to
review until today.

>> > Well, the TRY..CATCH in your prototype would catch any error that may be
>> > thrown in parse_expression, and the `set_language' must take care of
>> > changing the language, so I would say that is enough...
>> 
>> OK - I will send an updated patch that makes things a little cleaner.
>> I didn't know whether it was OK to default to type long makes much
>> sense when the probe says the parameter should be using type "mutex_t".

I remember we had the same problem (i.e., not parsing using language_c)
on SystemTap SDT probes as well.  Coincidentally or not, you triggered
the problem twice!

> Here it is.
>
> gdb/ChangeLog:
>
>         * dtrace-probe.c (dtrace_process_dof_probe): Contain any
>         exception raised while parsing the probe arguments.
>         Force parsing to be done using the C language parser.
>         * expression.h (parse_expression_with_language): Declare.
>         * parse.c (parse_expression_with_language): New function.
>
> Tested on sparc-solaris.
>
> -- 
> Joel
>
> From ba8991270e994cd96f92316932f65f96e47bf329 Mon Sep 17 00:00:00 2001
> From: Joel Brobecker <brobecker@adacore.com>
> Date: Thu, 26 Mar 2015 19:14:03 +0100
> Subject: [PATCH] dtrace-probe: Handle error while parsing probe argument.
>
> The debugger on Solaris has been broken since the introduction of
> DTrace probe support:
>
>     (gdb) start
>     Temporary breakpoint 1 at 0x80593bc: file simple_main.adb, line 4.
>     Starting program: /[...]/simple_main
>     [Thread debugging using libthread_db enabled]
>     No definition of "mutex_t" in current context.
>
> The problem occurs while trying to parse a probe's arguument,

"argument"

> and the exception propagates all the way to the top. This patch
> fixes the issue by containing the exception and falling back on
> using the "long" builtin type if the argument's type could not
> be determined.
>
> Also, the parsing should be done using the C language parser.
>
> gdb/ChangeLog:
>
>         * dtrace-probe.c (dtrace_process_dof_probe): Contain any
>         exception raised while parsing the probe arguments.
>         Force parsing to be done using the C language parser.
>         * expression.h (parse_expression_with_language): Declare.
>         * parse.c (parse_expression_with_language): New function.
> ---
>  gdb/dtrace-probe.c |   14 ++++++++++++--
>  gdb/expression.h   |    3 +++
>  gdb/parse.c        |   22 ++++++++++++++++++++++
>  3 files changed, 37 insertions(+), 2 deletions(-)
>
> diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
> index 491d853..ff7ce7d 100644
> --- a/gdb/dtrace-probe.c
> +++ b/gdb/dtrace-probe.c
> @@ -427,8 +427,18 @@ dtrace_process_dof_probe (struct objfile *objfile,
>  	     this does not work then we set the type to `long
>  	     int'.  */
>            arg.type = builtin_type (gdbarch)->builtin_long;
> -	  expr = parse_expression (arg.type_str);
> -	  if (expr->elts[0].opcode == OP_TYPE)
> +
> +	  TRY
> +	    {
> +	      expr = parse_expression_with_language (arg.type_str, language_c);
> +	    }
> +	  CATCH (ex, RETURN_MASK_ERROR)
> +	    {
> +	      expr = NULL;
> +	    }
> +	  END_CATCH
> +
> +	  if (expr != NULL && expr->elts[0].opcode == OP_TYPE)
>  	    arg.type = expr->elts[1].type;
>  
>  	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);

This part looks OK.

> diff --git a/gdb/expression.h b/gdb/expression.h
> index f5cd0e5..d08ce05 100644
> --- a/gdb/expression.h
> +++ b/gdb/expression.h
> @@ -97,6 +97,9 @@ struct expression
>  
>  extern struct expression *parse_expression (const char *);
>  
> +extern struct expression *parse_expression_with_language (const char *string,
> +							  enum language lang);
> +
>  extern struct expression *parse_expression_in_context (const char *, int);
>  
>  extern struct type *parse_field_expression (char *, char **);
> diff --git a/gdb/parse.c b/gdb/parse.c
> index 2ffe52e..bc95cf1 100644
> --- a/gdb/parse.c
> +++ b/gdb/parse.c
> @@ -1268,6 +1268,28 @@ parse_expression (const char *string)
>    return exp;
>  }
>  
> +/* Same as parse_expression, but using the given language (LANG)
> +   to parse the expression.  */
> +
> +struct expression *
> +parse_expression_with_language (const char *string, enum language lang)
> +{
> +  struct cleanup *old_chain = NULL;
> +  struct expression *expr;
> +
> +  if (current_language->la_language != language_c)
> +    {
> +      old_chain = make_cleanup_restore_current_language ();
> +      set_language (language_c);
> +    }

Here I think you meant to use "lang" instead of "language_c", right?

> +
> +  expr = parse_expression (string);
> +
> +  if (old_chain != NULL)
> +    do_cleanups (old_chain);
> +  return expr;
> +}
> +
>  /* As for parse_expression, except that if VOID_CONTEXT_P, then
>     no value is expected from the expression.  */
>  
> -- 
> 1.7.10.4
>

OK with the fix above.

Thanks,

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 18:53             ` Sergio Durigan Junior
@ 2015-03-26 21:00               ` Joel Brobecker
  2015-03-27  9:47                 ` gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.) Tobias Burnus
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-26 21:00 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: Jose E. Marchesi, gdb-patches

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

> >> > Well, the TRY..CATCH in your prototype would catch any error that may be
> >> > thrown in parse_expression, and the `set_language' must take care of
> >> > changing the language, so I would say that is enough...
> >> 
> >> OK - I will send an updated patch that makes things a little cleaner.
> >> I didn't know whether it was OK to default to type long makes much
> >> sense when the probe says the parameter should be using type "mutex_t".
> 
> I remember we had the same problem (i.e., not parsing using language_c)
> on SystemTap SDT probes as well.  Coincidentally or not, you triggered
> the problem twice!

The curse of using a cool language on exotic platforms :-).

> > The problem occurs while trying to parse a probe's arguument,
> 
> "argument"
> > +  if (current_language->la_language != language_c)
> > +    {
> > +      old_chain = make_cleanup_restore_current_language ();
> > +      set_language (language_c);
> > +    }
> 
> Here I think you meant to use "lang" instead of "language_c", right?

Duh...

Thanks for reviewing the entire patch! Attached is what I just pushed.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Contain any
        exception raised while parsing the probe arguments.
        Force parsing to be done using the C language parser.
        * expression.h (parse_expression_with_language): Declare.
        * parse.c (parse_expression_with_language): New function.

Tested on sparc-solaris and also on x86_64-linux, just for kicks.

-- 
Joel

[-- Attachment #2: 0001-dtrace-probe-Handle-error-while-parsing-probe-argume.patch --]
[-- Type: text/x-diff, Size: 4155 bytes --]

From 429e1e811b400f07b5a514ea6b8a70b28e2d7ee9 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Thu, 26 Mar 2015 19:14:03 +0100
Subject: [PATCH] dtrace-probe: Handle error while parsing probe argument.

The debugger on Solaris has been broken since the introduction of
DTrace probe support:

    (gdb) start
    Temporary breakpoint 1 at 0x80593bc: file simple_main.adb, line 4.
    Starting program: /[...]/simple_main
    [Thread debugging using libthread_db enabled]
    No definition of "mutex_t" in current context.

The problem occurs while trying to parse a probe's argument,
and the exception propagates all the way to the top. This patch
fixes the issue by containing the exception and falling back on
using the "long" builtin type if the argument's type could not
be determined.

Also, the parsing should be done using the C language parser.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Contain any
        exception raised while parsing the probe arguments.
        Force parsing to be done using the C language parser.
        * expression.h (parse_expression_with_language): Declare.
        * parse.c (parse_expression_with_language): New function.
---
 gdb/ChangeLog      |  8 ++++++++
 gdb/dtrace-probe.c | 14 ++++++++++++--
 gdb/expression.h   |  3 +++
 gdb/parse.c        | 22 ++++++++++++++++++++++
 4 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 70026d0..150b29a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2015-03-26  Joel Brobecker  <brobecker@adacore.com>
+
+	* dtrace-probe.c (dtrace_process_dof_probe): Contain any
+	exception raised while parsing the probe arguments.
+	Force parsing to be done using the C language parser.
+	* expression.h (parse_expression_with_language): Declare.
+	* parse.c (parse_expression_with_language): New function.
+
 2015-03-26  Jon Turney  <jon.turney@dronecode.org.uk>
 
 	* MAINTAINERS (Write After Approval): Add "Jon Turney".
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 491d853..ff7ce7d 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -427,8 +427,18 @@ dtrace_process_dof_probe (struct objfile *objfile,
 	     this does not work then we set the type to `long
 	     int'.  */
           arg.type = builtin_type (gdbarch)->builtin_long;
-	  expr = parse_expression (arg.type_str);
-	  if (expr->elts[0].opcode == OP_TYPE)
+
+	  TRY
+	    {
+	      expr = parse_expression_with_language (arg.type_str, language_c);
+	    }
+	  CATCH (ex, RETURN_MASK_ERROR)
+	    {
+	      expr = NULL;
+	    }
+	  END_CATCH
+
+	  if (expr != NULL && expr->elts[0].opcode == OP_TYPE)
 	    arg.type = expr->elts[1].type;
 
 	  VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
diff --git a/gdb/expression.h b/gdb/expression.h
index 15ed354..6af8331 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -97,6 +97,9 @@ struct expression
 
 extern struct expression *parse_expression (const char *);
 
+extern struct expression *parse_expression_with_language (const char *string,
+							  enum language lang);
+
 extern struct type *parse_expression_for_completion (const char *, char **,
 						     enum type_code *);
 
diff --git a/gdb/parse.c b/gdb/parse.c
index ec23dbb..6b59c4f 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -1268,6 +1268,28 @@ parse_expression (const char *string)
   return exp;
 }
 
+/* Same as parse_expression, but using the given language (LANG)
+   to parse the expression.  */
+
+struct expression *
+parse_expression_with_language (const char *string, enum language lang)
+{
+  struct cleanup *old_chain = NULL;
+  struct expression *expr;
+
+  if (current_language->la_language != lang)
+    {
+      old_chain = make_cleanup_restore_current_language ();
+      set_language (lang);
+    }
+
+  expr = parse_expression (string);
+
+  if (old_chain != NULL)
+    do_cleanups (old_chain);
+  return expr;
+}
+
 /* Parse STRING as an expression.  If parsing ends in the middle of a
    field reference, return the type of the left-hand-side of the
    reference; furthermore, if the parsing ends in the field name,
-- 
1.9.1


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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 17:50         ` Joel Brobecker
  2015-03-26 18:43           ` Joel Brobecker
@ 2015-03-26 23:39           ` Jose E. Marchesi
  2015-03-31 17:29           ` Jose E. Marchesi
  2 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-03-26 23:39 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches


    > Could you please send me your sparc-solaris reproducer?
    
    Thanks for the offer to help! Sadly, the SEGV doesn't seem to
    happen on sparc-solaris, it seems. Once I apply the patch above,
    I pretty much get normal results back (yay!).
    
    So, the problem appears to be specific to x86-solaris. I didn't know
    the DOF program was embedded in the executable, but I suspect there is
    a problem in its contents. How do you think we should proceed?
    
Hmm, this may be an endianness problem:

/* DOF supports two different encodings: MSB (big-endian) and LSB
   (little-endian).  The encoding is itself encoded in the DOF header.
   The following function returns an unsigned value in the host
   endianness.  */

#define DOF_UINT(dof, field)						\
  extract_unsigned_integer ((gdb_byte *) &(field),			\
			    sizeof ((field)),				\
			    (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \
			      == DTRACE_DOF_ENCODE_MSB)			\
			     ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE))


We know for a fact that the implementation works properly on a
little-endian host (x86) and little-endian DOF data (generated by either
pdtrace or dtrace).

I would need to look at the x86-solaris binaries you are using.  Maybe
dtrace on that platform is generating big-endian DOF data in the
little-endian platform and the implementation is not handling that
properly.

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

* Re: gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.)
  2015-03-26 21:00               ` Joel Brobecker
@ 2015-03-27  9:47                 ` Tobias Burnus
  2015-03-27 13:42                   ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Tobias Burnus @ 2015-03-27  9:47 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

Hi all,

I think this patch (commit 429e1e811b400f07b5a514ea6b8a70b28e2d7ee9) causes
gdb's compilation to fail with GCC 4.4.7 (RHEL 6 system compiler) as follows;
it does work with GCC 5.

cc1: warnings being treated as errors
../../gdb/dtrace-probe.c: In function ‘dtrace_process_dof_probe’:
../../gdb/dtrace-probe.c:416: error: ‘expr’ may be used uninitialized in this function
make[2]: *** [dtrace-probe.o] Error 1


I think that looks spurious as the code looks fine (i.e. GCC is overzaelous), still,
a "= NULL" should harm.

Tobias


   414          {
   415            struct dtrace_probe_arg arg;
   416            struct expression *expr;
...
   431            TRY
   432              {
   433                expr = parse_expression_with_language (arg.type_str, language_c);
   434              }
   435            CATCH (ex, RETURN_MASK_ERROR)
   436              {
   437                expr = NULL;
   438              }
   439            END_CATCH
   440
   441            if (expr != NULL && expr->elts[0].opcode == OP_TYPE)
   442              arg.type = expr->elts[1].type;

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

* Re: gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.)
  2015-03-27  9:47                 ` gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.) Tobias Burnus
@ 2015-03-27 13:42                   ` Joel Brobecker
  2015-03-27 15:18                     ` Tobias Burnus
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-27 13:42 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gdb-patches

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

> I think this patch (commit 429e1e811b400f07b5a514ea6b8a70b28e2d7ee9) causes
> gdb's compilation to fail with GCC 4.4.7 (RHEL 6 system compiler) as follows;
> it does work with GCC 5.
> 
> cc1: warnings being treated as errors
> ../../gdb/dtrace-probe.c: In function ‘dtrace_process_dof_probe’:
> ../../gdb/dtrace-probe.c:416: error: ‘expr’ may be used uninitialized in this function
> make[2]: *** [dtrace-probe.o] Error 1
> 
> 
> I think that looks spurious as the code looks fine (i.e. GCC is overzaelous), still,
> a "= NULL" should harm.

Would you mind checking that the attached patch fixes the problem?

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Initialize expr to NULL.

Tested on x86_64-linux by rebuilding GDB.

Thank you,
-- 
Joel

[-- Attachment #2: 0001-Initialize-EXPR-in-dtrace-probe-dtrace_process_dof_p.patch --]
[-- Type: text/x-diff, Size: 1395 bytes --]

From 9b1d494cfb04c4d05252af84545f060bd67bcb87 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Fri, 27 Mar 2015 06:37:34 -0700
Subject: [PATCH] Initialize EXPR in dtrace-probe::dtrace_process_dof_probe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

GCC 4.4.7 generates the following warning:

 | cc1: warnings being treated as errors
 | dtrace-probe.c: In function ‘dtrace_process_dof_probe’:
 | dtrace-probe.c:416: error: ‘expr’ may be used uninitialized in this function
 | make[2]: *** [dtrace-probe.o] Error 1

Later versions (GCC 5) do a better job and don't generate the warning,
but it does not hurt to pre-initialize "expr" to NULL.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof_probe): Initialize expr to NULL.
---
 gdb/dtrace-probe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index ff7ce7d..3f2548d 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -413,7 +413,7 @@ dtrace_process_dof_probe (struct objfile *objfile,
       for (j = 0; j < ret->probe_argc; j++)
 	{
 	  struct dtrace_probe_arg arg;
-	  struct expression *expr;
+	  struct expression *expr = NULL;
 
 	  /* Set arg.expr to ensure all fields in expr are initialized and
 	     the compiler will not warn when arg is used.  */
-- 
1.9.1


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

* Re: gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.)
  2015-03-27 13:42                   ` Joel Brobecker
@ 2015-03-27 15:18                     ` Tobias Burnus
  2015-03-27 15:27                       ` [pushed] " Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Tobias Burnus @ 2015-03-27 15:18 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Fri, Mar 27, 2015 at 06:42:52AM -0700, Joel Brobecker wrote:
> > I think that looks spurious as the code looks fine (i.e. GCC is overzaelous), still,
> > a "= NULL" should harm.
> 
> Would you mind checking that the attached patch fixes the problem?

Yes, it now also compiles with GCC 4.4. Thanks for the fix!

Tobias

>         * dtrace-probe.c (dtrace_process_dof_probe): Initialize expr to NULL.
> ---
>  gdb/dtrace-probe.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
> index ff7ce7d..3f2548d 100644
> --- a/gdb/dtrace-probe.c
> +++ b/gdb/dtrace-probe.c
> @@ -413,7 +413,7 @@ dtrace_process_dof_probe (struct objfile *objfile,
>        for (j = 0; j < ret->probe_argc; j++)
>  	{
>  	  struct dtrace_probe_arg arg;
> -	  struct expression *expr;
> +	  struct expression *expr = NULL;
>  
>  	  /* Set arg.expr to ensure all fields in expr are initialized and
>  	     the compiler will not warn when arg is used.  */
> -- 
> 1.9.1
> 

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

* [pushed] Re: gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.)
  2015-03-27 15:18                     ` Tobias Burnus
@ 2015-03-27 15:27                       ` Joel Brobecker
  2015-03-27 16:58                         ` H.J. Lu
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-27 15:27 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gdb-patches

> > Would you mind checking that the attached patch fixes the problem?
> 
> Yes, it now also compiles with GCC 4.4. Thanks for the fix!
> 
> Tobias
> 
> >         * dtrace-probe.c (dtrace_process_dof_probe): Initialize expr to NULL.

Excellent, thanks for reporting the problem and checking the fix
for me. Patch is now in.

-- 
Joel

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

* Re: [pushed] Re: gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.)
  2015-03-27 15:27                       ` [pushed] " Joel Brobecker
@ 2015-03-27 16:58                         ` H.J. Lu
  0 siblings, 0 replies; 51+ messages in thread
From: H.J. Lu @ 2015-03-27 16:58 UTC (permalink / raw)
  To: Joel Brobecker, Binutils; +Cc: Tobias Burnus, GDB

On Fri, Mar 27, 2015 at 8:27 AM, Joel Brobecker <brobecker@adacore.com> wrote:
>> > Would you mind checking that the attached patch fixes the problem?
>>
>> Yes, it now also compiles with GCC 4.4. Thanks for the fix!
>>
>> Tobias
>>
>> >         * dtrace-probe.c (dtrace_process_dof_probe): Initialize expr to NULL.
>
> Excellent, thanks for reporting the problem and checking the fix
> for me. Patch is now in.

FWIW, there are other similar places in binutils-gdb tree:

https://sourceware.org/ml/binutils/2015-03/msg00368.html

I suggested a macro, like

#define SILENCE_UNIITITALIZED_WARNING(var) ....

and do

struct bfd_link_hash_entry SILENCE_UNIITITALIZED_WARNING (ehdr_start_save);


-- 
H.J.

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-26 17:50         ` Joel Brobecker
  2015-03-26 18:43           ` Joel Brobecker
  2015-03-26 23:39           ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
@ 2015-03-31 17:29           ` Jose E. Marchesi
  2015-03-31 18:47             ` Joel Brobecker
  2 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-03-31 17:29 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches


Hi Joel.

    >     And once I had that fixed, the next issue that I looked at was:
    >     
    >         (gdb) b adainit
    >         Breakpoint 1 at 0x8051f03
    >         (gdb) run
    >         Starting program: /[...]/a
    >         [Thread debugging using libthread_db enabled]
    >         zsh: 12378 segmentation fault (core dumped)  /[...]/gdb -q a
    >     
    >     This is where I'm getting even more out of my league, here.
    >     The SEGV happens on the following line:
    >     
    >     377           uint32_t enabler_offset
    >     378             = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
    > 
    > I will debug that SIGSEGV in solaris, but the problem seems to be
    > related to the DOF program embedded in your program, more than to the
    > platform.
    > 
    > Could you please send me your sparc-solaris reproducer?
    
    Thanks for the offer to help! Sadly, the SEGV doesn't seem to
    happen on sparc-solaris, it seems. Once I apply the patch above,
    I pretty much get normal results back (yay!).
    
    So, the problem appears to be specific to x86-solaris. I didn't know
    the DOF program was embedded in the executable, but I suspect there is
    a problem in its contents.

I just tried the following in a x86-solaris machine, using todays git
GDB:

$ uname -a
SunOS solaris-x86 5.11 11.1 i86pc i386 i86pc
$ cat > foo.d <<EOF
provider test {
 probe progress__counter (char *, int);
};
EOF
$ cat > foo.c <<EOF
#include "foo.h"

int
main ()
{
  char *name = "application";
  int i = 0;

  while (i < 10)
  {
    i++;
    if (TEST_PROGRESS_COUNTER_ENABLED())
      TEST_PROGRESS_COUNTER (name, i);
  }

  return 0;
}
EOF
$ dtrace -h -s foo.d -o foo.h
$ gcc -c foo.c
$ dtrace -G -s foo.d -o foo-p.o foo.o
$ gcc -o foo foo.o foo-p.o
$ gdb foo
[...]
(gdb) info probes
Type   Provider Name             Where      Enabled Object
dtrace test     progress-counter 0x08051024 unknown /export/home/jose/binutils-gdb/build/foo
(gdb) disas main
Dump of assembler code for function main:
0x08050fec <+0>:     push   %ebp
0x08050fed <+1>:     mov    %esp,%ebp
0x08050fef <+3>:     and    $0xfffffff0,%esp
0x08050ff2 <+6>:     sub    $0x20,%esp
0x08050ff5 <+9>:     movl   $0x80514f0,0x18(%esp)
0x08050ffd <+17>:    movl   $0x0,0x1c(%esp)
0x08051005 <+25>:    jmp    0x8051029 <main+61>
0x08051007 <+27>:    addl   $0x1,0x1c(%esp)
0x0805100c <+32>:    xor    %eax,%eax
0x0805100e <+34>:    nop
0x0805100f <+35>:    nop
0x08051010 <+36>:    nop
0x08051011 <+37>:    test   %eax,%eax
0x08051013 <+39>:    je     0x8051029 <main+61>
0x08051015 <+41>:    mov    0x1c(%esp),%eax
0x08051019 <+45>:    mov    %eax,0x4(%esp)
0x0805101d <+49>:    mov    0x18(%esp),%eax
0x08051021 <+53>:    mov    %eax,(%esp)
0x08051024 <+56>:    nop
0x08051025 <+57>:    nop
0x08051026 <+58>:    nop
0x08051027 <+59>:    nop
0x08051028 <+60>:    nop
0x08051029 <+61>:    cmpl   $0x9,0x1c(%esp)
0x0805102e <+66>:    jle    0x8051007 <main+27>
0x08051030 <+68>:    mov    $0x0,%eax
0x08051035 <+73>:    leave
0x08051036 <+74>:    ret
End of assembler dump.
(gdb)

In this system DTrace generates little-endian DOF data, and it looks
like GDB handles it just fine.  I still think the problem you observed
is related to endianness, but I cannot be sure without looking at the
contents of the DOF program embedded in your binaries...

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-31 17:29           ` Jose E. Marchesi
@ 2015-03-31 18:47             ` Joel Brobecker
  2015-03-31 19:54               ` Jose E. Marchesi
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-03-31 18:47 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Sergio Durigan Junior, gdb-patches

Hi Jose,

> I just tried the following in a x86-solaris machine, using todays git
> GDB:
[...]
> In this system DTrace generates little-endian DOF data, and it looks
> like GDB handles it just fine.  I still think the problem you observed
> is related to endianness, but I cannot be sure without looking at the
> contents of the DOF program embedded in your binaries...

Sorry, I was going to send you an email this morning, and then got
carried away by other duties... :-(

I've been able to reproduce the problem, but when I checked again
with a non-AdaCore debugger, the problem went away. I'm not really
sure whether this indicates whether this is an issue caused by
some of our local changes, or whether this is just a latent bug
that gets triggered by those local changes. Either way, it felt like
I would have no choice but to get more familiar with how those probes
work. The problem is that I'm short on time again. But, if you have
any kind of document describing how this data is laid out in the
binary, I'm very interested.

Sorry I waited so long before getting back to you!

-- 
Joel

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-31 18:47             ` Joel Brobecker
@ 2015-03-31 19:54               ` Jose E. Marchesi
  2015-08-06 21:31                 ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-03-31 19:54 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches

    
    I've been able to reproduce the problem, but when I checked again
    with a non-AdaCore debugger, the problem went away. I'm not really
    sure whether this indicates whether this is an issue caused by
    some of our local changes, or whether this is just a latent bug
    that gets triggered by those local changes. Either way, it felt like
    I would have no choice but to get more familiar with how those probes
    work. The problem is that I'm short on time again. But, if you have
    any kind of document describing how this data is laid out in the
    binary, I'm very interested.
    
I don't know of any document describing the DOF layout.  I would suggest
you to take a look to the script gdb/testsuite/lib/pdtrace.in.  It
creates and populates DOF sections and it documents the structure of the
generated data.

Feel free to send me any question you may have regarding DOF.  I will
try to help even if I am not a DOF expert myself :)

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-03-31 19:54               ` Jose E. Marchesi
@ 2015-08-06 21:31                 ` Joel Brobecker
  2015-08-07  2:03                   ` Sergio Durigan Junior
                                     ` (2 more replies)
  0 siblings, 3 replies; 51+ messages in thread
From: Joel Brobecker @ 2015-08-06 21:31 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Sergio Durigan Junior, gdb-patches

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

I finally had a bit of time to look into this again. I concluded
that the DOF data is invalid, or follows a format that's different
from the one that GDB expected, and so added some code to detect
and ignore... Attached is the patch with full explanation. Does it
make sense to you?

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
        data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
        smaller than expected.

Tested on x86_64-linux (official GDB testsuite) + x86-solaris
(AdaCore's testsuite).

Thanks,
-- 
Joel

[-- Attachment #2: 0001-DTRACE-ignore-invalid-DOF-provider-sections.patch --]
[-- Type: text/x-diff, Size: 4308 bytes --]

From 84179e3ce4008f36cbdbb4edf040d94b5f03b4c2 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Thu, 6 Aug 2015 22:13:32 +0200
Subject: [PATCH] [DTRACE] ignore invalid DOF provider sections

On x86-solaris 10, we noticed that starting a program would sometimes
cause the debugger to crash. For instance:

    % gdb a
    (gdb) break adainit
    Breakpoint 1 at 0x8051f03
    (gdb) run
    Starting program: /[...]/a
    [Thread debugging using libthread_db enabled]
    zsh: 24398 segmentation fault (core dumped)  /[...]/gdb a

The exception occurs in dtrace_process_dof_probe, while trying
to process each probe referenced by a DTRACE_DOF_SECT_TYPE_PROVIDER
DOF section from /lib/libc.so.1. For reference, the ELF section
in that shared library providing the DOF data has the following
characteristics:

    Idx Name          Size      VMA       LMA       File off  Algn
     14 .SUNW_dof     0000109d  000b4398  000b4398  000b4398  2**3
                      CONTENTS, ALLOC, LOAD, READONLY, DATA

The function dtrace_process_dof gets passed the contents of that
ELF section, which allows is to determine the location of the table
where all DOF sections are described. I dumped the contents of
each DOF section as seen by GDB, and it seemed to be plausible,
because the offset of each DOF section was pretty much equal to
the sum of the offset and size of the previous DOF section. Also,
the offset + sum of the last section corresponds to the size of
the .SUNW_dof section.

Things start to break down when processing one of the DOF sections
that has a type of DTRACE_DOF_SECT_TYPE_PROVIDER. It gets the contents
of this DOF section via:

        struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
          DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));

Said more simply, the struct dtrace_dof_provider data is at
section->dofs_offset of the entire DOF contents. Given that
the contents of SECTION seemed to make sense, so far so good.

However, what SECTION tells us is that our DOF provider section
is 40 bytes long:

    (gdb) print *section
    $36 = {dofs_type = 15, dofs_align = 4, dofs_flags = 1,
           dofs_entsize = 0, dofs_offset = 3264, dofs_size = 40}
                                                 ^^^^^^^^^^^^^^

But on the other hand:

    (gdb) p sizeof (struct dtrace_dof_provider)
    $54 = 44

In other words GDB expected a bigger DOF section and when we try to
fetch the value of the last field of that DOF section (dofpv_prenoffs)...

    eoffsets_s = DTRACE_DOF_SECT (dof,
                                  DOF_UINT (dof, provider->dofpv_prenoffs));

... we end up reading data that actually belongs to another DOF
section, and therefore irrelevant. This in turn means that the value
of eofftab gets incorrectly set, since it depends on eoffsets_s:

    eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));

This invalid address quickly catches up to us when we pass it to
dtrace_process_dof_probe shortly after, where we crash because
we try to subscript it:

    Program received signal SIGSEGV, Segmentation fault.
    0x08155bba in dtrace_process_dof_probe ([...]) at [...]/dtrace-probe.c:378
    378             = ((uint32_t *) eofftab)[...];

This patch fixes the issue by detecting provider DOF sections
that are smaller than expected, and discarding the DOF data.

gdb/ChangeLog:

        * dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
        data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
        smaller than expected.
---
 gdb/dtrace-probe.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 3f2548d..9816f07 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -519,6 +519,14 @@ dtrace_process_dof (asection *sect, struct objfile *objfile,
 	unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
 	int num_probes;
 
+	if (DOF_UINT (dof, section->dofs_size)
+	    < sizeof (struct dtrace_dof_provider))
+	  {
+	    /* The section is smaller than expected, so do not use it.
+	       This has been observed on x86-solaris 10.  */
+	    goto invalid_dof_data;
+	  }
+
 	/* Very, unlikely, but could crash gdb if not handled
 	   properly.  */
 	if (entsize == 0)
-- 
1.7.10.4


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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-06 21:31                 ` Joel Brobecker
@ 2015-08-07  2:03                   ` Sergio Durigan Junior
  2015-08-07 15:20                     ` Joel Brobecker
  2015-08-07 13:05                   ` Jose E. Marchesi
  2015-08-07 13:14                   ` Jose E. Marchesi
  2 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-08-07  2:03 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jose E. Marchesi, gdb-patches

On Thursday, August 06 2015, Joel Brobecker wrote:

> I finally had a bit of time to look into this again. I concluded
> that the DOF data is invalid, or follows a format that's different
> from the one that GDB expected, and so added some code to detect
> and ignore... Attached is the patch with full explanation. Does it
> make sense to you?
>
> gdb/ChangeLog:
>
>         * dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
>         data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
>         smaller than expected.
>
> Tested on x86_64-linux (official GDB testsuite) + x86-solaris
> (AdaCore's testsuite).

Pretty nice investigation, Joel!

This patch makes sense to me and is OK to go in (it just has a small
typo below).

Something I don't like about this goto scheme is that it doesn't contain
useful information as to why the section has been discarded ("... does
not contain valid DOF data" is too generic).  But I'm just speaking my
mind here; this has nothing to do with your patch :-).

> Thanks,
> -- 
> Joel
>
> From 84179e3ce4008f36cbdbb4edf040d94b5f03b4c2 Mon Sep 17 00:00:00 2001
> From: Joel Brobecker <brobecker@adacore.com>
> Date: Thu, 6 Aug 2015 22:13:32 +0200
> Subject: [PATCH] [DTRACE] ignore invalid DOF provider sections
>
> On x86-solaris 10, we noticed that starting a program would sometimes
> cause the debugger to crash. For instance:
>
>     % gdb a
>     (gdb) break adainit
>     Breakpoint 1 at 0x8051f03
>     (gdb) run
>     Starting program: /[...]/a
>     [Thread debugging using libthread_db enabled]
>     zsh: 24398 segmentation fault (core dumped)  /[...]/gdb a
>
> The exception occurs in dtrace_process_dof_probe, while trying
> to process each probe referenced by a DTRACE_DOF_SECT_TYPE_PROVIDER
> DOF section from /lib/libc.so.1. For reference, the ELF section
> in that shared library providing the DOF data has the following
> characteristics:
>
>     Idx Name          Size      VMA       LMA       File off  Algn
>      14 .SUNW_dof     0000109d  000b4398  000b4398  000b4398  2**3
>                       CONTENTS, ALLOC, LOAD, READONLY, DATA
>
> The function dtrace_process_dof gets passed the contents of that
> ELF section, which allows is to determine the location of the table
                            ^^

"it" ?

> where all DOF sections are described. I dumped the contents of
> each DOF section as seen by GDB, and it seemed to be plausible,
> because the offset of each DOF section was pretty much equal to
> the sum of the offset and size of the previous DOF section. Also,
> the offset + sum of the last section corresponds to the size of
> the .SUNW_dof section.
>
> Things start to break down when processing one of the DOF sections
> that has a type of DTRACE_DOF_SECT_TYPE_PROVIDER. It gets the contents
> of this DOF section via:
>
>         struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
>           DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
>
> Said more simply, the struct dtrace_dof_provider data is at
> section->dofs_offset of the entire DOF contents. Given that
> the contents of SECTION seemed to make sense, so far so good.
>
> However, what SECTION tells us is that our DOF provider section
> is 40 bytes long:
>
>     (gdb) print *section
>     $36 = {dofs_type = 15, dofs_align = 4, dofs_flags = 1,
>            dofs_entsize = 0, dofs_offset = 3264, dofs_size = 40}
>                                                  ^^^^^^^^^^^^^^
>
> But on the other hand:
>
>     (gdb) p sizeof (struct dtrace_dof_provider)
>     $54 = 44
>
> In other words GDB expected a bigger DOF section and when we try to
> fetch the value of the last field of that DOF section (dofpv_prenoffs)...
>
>     eoffsets_s = DTRACE_DOF_SECT (dof,
>                                   DOF_UINT (dof, provider->dofpv_prenoffs));
>
> ... we end up reading data that actually belongs to another DOF
> section, and therefore irrelevant. This in turn means that the value
> of eofftab gets incorrectly set, since it depends on eoffsets_s:
>
>     eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
>
> This invalid address quickly catches up to us when we pass it to
> dtrace_process_dof_probe shortly after, where we crash because
> we try to subscript it:
>
>     Program received signal SIGSEGV, Segmentation fault.
>     0x08155bba in dtrace_process_dof_probe ([...]) at [...]/dtrace-probe.c:378
>     378             = ((uint32_t *) eofftab)[...];
>
> This patch fixes the issue by detecting provider DOF sections
> that are smaller than expected, and discarding the DOF data.
>
> gdb/ChangeLog:
>
>         * dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
>         data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
>         smaller than expected.
> ---
>  gdb/dtrace-probe.c |    8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
> index 3f2548d..9816f07 100644
> --- a/gdb/dtrace-probe.c
> +++ b/gdb/dtrace-probe.c
> @@ -519,6 +519,14 @@ dtrace_process_dof (asection *sect, struct objfile *objfile,
>  	unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
>  	int num_probes;
>  
> +	if (DOF_UINT (dof, section->dofs_size)
> +	    < sizeof (struct dtrace_dof_provider))
> +	  {
> +	    /* The section is smaller than expected, so do not use it.
> +	       This has been observed on x86-solaris 10.  */
> +	    goto invalid_dof_data;
> +	  }
> +
>  	/* Very, unlikely, but could crash gdb if not handled
>  	   properly.  */
>  	if (entsize == 0)
> -- 
> 1.7.10.4
>

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-06 21:31                 ` Joel Brobecker
  2015-08-07  2:03                   ` Sergio Durigan Junior
@ 2015-08-07 13:05                   ` Jose E. Marchesi
  2015-08-07 13:14                   ` Jose E. Marchesi
  2 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-08-07 13:05 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches


Hi Joel.

    I finally had a bit of time to look into this again. I concluded
    that the DOF data is invalid, or follows a format that's different
    from the one that GDB expected, and so added some code to detect
    and ignore... Attached is the patch with full explanation. Does it
    make sense to you?

Yes, definitely, thanks for the fix!

I will pass this information to the DTrace hackers.  It would be nice to
figure out why such an inconsistent DOF data is being generated in
solarix-x86.

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-06 21:31                 ` Joel Brobecker
  2015-08-07  2:03                   ` Sergio Durigan Junior
  2015-08-07 13:05                   ` Jose E. Marchesi
@ 2015-08-07 13:14                   ` Jose E. Marchesi
  2015-08-07 14:11                     ` Jose E. Marchesi
  2 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-08-07 13:14 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches

     
    +	if (DOF_UINT (dof, section->dofs_size)
    +	    < sizeof (struct dtrace_dof_provider))
    +	  {
    +	    /* The section is smaller than expected, so do not use it.
    +	       This has been observed on x86-solaris 10.  */
    +	    goto invalid_dof_data;
    +	  }
    +

It looks to me that at some point a new field was probably added to the
struct dtrace_dof_provider, changing its size.  If the DOF sections
found in the solaris-x86 binaries were generated before the change, that
would explain the discrepancy in size.

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-07 13:14                   ` Jose E. Marchesi
@ 2015-08-07 14:11                     ` Jose E. Marchesi
  2015-08-07 15:12                       ` Joel Brobecker
  0 siblings, 1 reply; 51+ messages in thread
From: Jose E. Marchesi @ 2015-08-07 14:11 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Sergio Durigan Junior, gdb-patches

         
        +	if (DOF_UINT (dof, section->dofs_size)
        +	    < sizeof (struct dtrace_dof_provider))
        +	  {
        +	    /* The section is smaller than expected, so do not use it.
        +	       This has been observed on x86-solaris 10.  */
        +	    goto invalid_dof_data;
        +	  }
        +
    
    It looks to me that at some point a new field was probably added to the
    struct dtrace_dof_provider, changing its size.

Confirmed: DOF version 2 added support for is-enabled probes, and the
struct dtrace_dof_provider got a new 4 bytes field:

@@ -719,6 +722,7 @@ typedef struct dof_provider {
        dof_attr_t dofpv_funcattr;      /* function attributes */
        dof_attr_t dofpv_nameattr;      /* name attributes */
        dof_attr_t dofpv_argsattr;      /* args attributes */
+       dof_secidx_t dofpv_prenoffs;    /* link to DOF_SECT_PRENOFFS section */
 } dof_provider_t;

Looks like your solaris-x86 binaries are embedding DOFv1 programs.  You
can check that by looking at dof->dofh_ident[6]: it will be 1 in a DOFv1
program and 2 in a DOFv2 program.

So... we can make GDB to look at the DOF version and then use a
different struct (struct dof_provider_v1 ?) when handling embedded
programs using the old format.

I can prepare a patch for this.  For testing purposes pdtrace can be
made to generate DOFv1 programs even in systems lacking an old enough
dtrace.

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-07 14:11                     ` Jose E. Marchesi
@ 2015-08-07 15:12                       ` Joel Brobecker
  2015-08-10  3:21                         ` Sergio Durigan Junior
  0 siblings, 1 reply; 51+ messages in thread
From: Joel Brobecker @ 2015-08-07 15:12 UTC (permalink / raw)
  To: Jose E. Marchesi; +Cc: Sergio Durigan Junior, gdb-patches

> Confirmed: DOF version 2 added support for is-enabled probes, and the
> struct dtrace_dof_provider got a new 4 bytes field:
> 
> @@ -719,6 +722,7 @@ typedef struct dof_provider {
>         dof_attr_t dofpv_funcattr;      /* function attributes */
>         dof_attr_t dofpv_nameattr;      /* name attributes */
>         dof_attr_t dofpv_argsattr;      /* args attributes */
> +       dof_secidx_t dofpv_prenoffs;    /* link to DOF_SECT_PRENOFFS section */
>  } dof_provider_t;
> 
> Looks like your solaris-x86 binaries are embedding DOFv1 programs.  You
> can check that by looking at dof->dofh_ident[6]: it will be 1 in a DOFv1
> program and 2 in a DOFv2 program.

I think I can confirm that. This is the contents of the .SUNW_dof
section for the .so file:

    Contents of section .SUNW_dof:
     b4398 7f444f46 01010102 08080000 00000000  .DOF............
                        ^^
                        ||

> So... we can make GDB to look at the DOF version and then use a
> different struct (struct dof_provider_v1 ?) when handling embedded
> programs using the old format.
>
> I can prepare a patch for this.  For testing purposes pdtrace can be
> made to generate DOFv1 programs even in systems lacking an old enough
> dtrace.

Sure. I would perhaps also consider the idea of not support DOF v1,
if v1 support is only of marginal value.

Also, I didn't say it before, I wasn't so sure that casting a binary
stream to a structure to read its contents was the best way to do
things. It can of works, but makes the code a little harder to read,
IMO, because accessing its contents requires the accessor macros.
Perhaps it might be better to just have decoding routines that take
the binary data and produce the corresponding struct, with the data
properly decoded. That way, you can add DOF version checks and decode
the data differently, without the rest of the code having to worry
about which version of the type they should be using. It's not obvious
to me that this way is better than the current way, but that's how
I would have tried it first... (just my 2 cents)

-- 
Joel

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-07  2:03                   ` Sergio Durigan Junior
@ 2015-08-07 15:20                     ` Joel Brobecker
  0 siblings, 0 replies; 51+ messages in thread
From: Joel Brobecker @ 2015-08-07 15:20 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: Jose E. Marchesi, gdb-patches

> Pretty nice investigation, Joel!
> 
> This patch makes sense to me and is OK to go in (it just has a small
> typo below).

Thanks! Patch just pushed with the tiny correction you indicated.

> Something I don't like about this goto scheme is that it doesn't contain
> useful information as to why the section has been discarded ("... does
> not contain valid DOF data" is too generic).  But I'm just speaking my
> mind here; this has nothing to do with your patch :-).

We could improve it indeed. For a rainy day...

-- 
Joel

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-07 15:12                       ` Joel Brobecker
@ 2015-08-10  3:21                         ` Sergio Durigan Junior
  2015-08-10 14:31                           ` Jose E. Marchesi
  0 siblings, 1 reply; 51+ messages in thread
From: Sergio Durigan Junior @ 2015-08-10  3:21 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jose E. Marchesi, gdb-patches

On Friday, August 07 2015, Joel Brobecker wrote:

>> So... we can make GDB to look at the DOF version and then use a
>> different struct (struct dof_provider_v1 ?) when handling embedded
>> programs using the old format.
>>
>> I can prepare a patch for this.  For testing purposes pdtrace can be
>> made to generate DOFv1 programs even in systems lacking an old enough
>> dtrace.

Thanks, Jose.  That would be much appreciated.

> Also, I didn't say it before, I wasn't so sure that casting a binary
> stream to a structure to read its contents was the best way to do
> things. It can of works, but makes the code a little harder to read,
> IMO, because accessing its contents requires the accessor macros.
> Perhaps it might be better to just have decoding routines that take
> the binary data and produce the corresponding struct, with the data
> properly decoded. That way, you can add DOF version checks and decode
> the data differently, without the rest of the code having to worry
> about which version of the type they should be using. It's not obvious
> to me that this way is better than the current way, but that's how
> I would have tried it first... (just my 2 cents)

I agree.  Something else really worth doing is creating a debug setting
for DTrace probes, and print useful information while decoding them.
Almost all (if not all) the information that Joel gathered using
external tools could have been printed from inside GDB.

Cheers,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* Re: [PATCH V4 5/9] New probe type: DTrace USDT probes.
  2015-08-10  3:21                         ` Sergio Durigan Junior
@ 2015-08-10 14:31                           ` Jose E. Marchesi
  0 siblings, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2015-08-10 14:31 UTC (permalink / raw)
  To: Sergio Durigan Junior; +Cc: Joel Brobecker, gdb-patches

    
    > Also, I didn't say it before, I wasn't so sure that casting a binary
    > stream to a structure to read its contents was the best way to do
    > things. It can of works, but makes the code a little harder to read,
    > IMO, because accessing its contents requires the accessor macros.
    > Perhaps it might be better to just have decoding routines that take
    > the binary data and produce the corresponding struct, with the data
    > properly decoded. That way, you can add DOF version checks and decode
    > the data differently, without the rest of the code having to worry
    > about which version of the type they should be using. It's not obvious
    > to me that this way is better than the current way, but that's how
    > I would have tried it first... (just my 2 cents)
    
    I agree.  Something else really worth doing is creating a debug setting
    for DTrace probes, and print useful information while decoding them.

That sounds like a good idea.  Let me work on that...

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

end of thread, other threads:[~2015-08-10 14:31 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-02 10:57 [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
2015-02-02 10:57 ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
2015-02-17  1:35   ` Sergio Durigan Junior
2015-03-25 19:14     ` Joel Brobecker
2015-03-26 16:15       ` Jose E. Marchesi
2015-03-26 17:50         ` Joel Brobecker
2015-03-26 18:43           ` Joel Brobecker
2015-03-26 18:53             ` Sergio Durigan Junior
2015-03-26 21:00               ` Joel Brobecker
2015-03-27  9:47                 ` gdb fails to compile with GCC 4.4.7 (was: [PATCH V4 5/9] New probe type: DTrace USDT probes.) Tobias Burnus
2015-03-27 13:42                   ` Joel Brobecker
2015-03-27 15:18                     ` Tobias Burnus
2015-03-27 15:27                       ` [pushed] " Joel Brobecker
2015-03-27 16:58                         ` H.J. Lu
2015-03-26 23:39           ` [PATCH V4 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
2015-03-31 17:29           ` Jose E. Marchesi
2015-03-31 18:47             ` Joel Brobecker
2015-03-31 19:54               ` Jose E. Marchesi
2015-08-06 21:31                 ` Joel Brobecker
2015-08-07  2:03                   ` Sergio Durigan Junior
2015-08-07 15:20                     ` Joel Brobecker
2015-08-07 13:05                   ` Jose E. Marchesi
2015-08-07 13:14                   ` Jose E. Marchesi
2015-08-07 14:11                     ` Jose E. Marchesi
2015-08-07 15:12                       ` Joel Brobecker
2015-08-10  3:21                         ` Sergio Durigan Junior
2015-08-10 14:31                           ` Jose E. Marchesi
2015-02-02 10:57 ` [PATCH V4 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
2015-02-17  1:14   ` Sergio Durigan Junior
2015-02-02 10:57 ` [PATCH V4 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
2015-02-02 11:18   ` Jose E. Marchesi
2015-02-17  1:53   ` Sergio Durigan Junior
2015-02-17  1:58     ` Sergio Durigan Junior
2015-02-17 11:32       ` Pedro Alves
2015-02-02 10:57 ` [PATCH V4 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
2015-02-17  1:13   ` Sergio Durigan Junior
2015-02-02 10:57 ` [PATCH V4 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
2015-02-02 16:03   ` Eli Zaretskii
2015-02-02 19:47     ` Jose E. Marchesi
2015-02-02 10:57 ` [PATCH V4 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
2015-02-02 16:03   ` Eli Zaretskii
2015-02-02 10:57 ` [PATCH V4 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
2015-02-02 16:01   ` Eli Zaretskii
2015-02-17  1:54   ` Sergio Durigan Junior
2015-02-02 10:57 ` [PATCH V4 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
2015-02-17  1:37   ` Sergio Durigan Junior
2015-02-02 10:57 ` [PATCH V4 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
2015-02-17  1:12   ` Sergio Durigan Junior
2015-02-16 13:20 ` [PATCH V4 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
2015-02-17  1:57 ` Sergio Durigan Junior
2015-02-17 11:56   ` Jose E. Marchesi

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