This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

static defined user probes


Here is an implementation of statically defined user probes which use
uprobes probes.  The test, testsuite/systemtap.base/sduprobes.{c,stp}
give a brief synopsis of the user interface.  (sduprobes.exp is not
completely fleshed out yet.) Currently STAP_PROBE_START turns on probing
and STAP_PROBEN define probe points.  STAP_PROBEN are defined the same
as DTRACE_PROBEN and give the name of the probe and the arguments to the
probe.  These macros are defined in sduprobes.h. The name of the probe
given to STAP_PROBEN is the label given to process(PROC).mark("LABEL").
Currently the landing pad for the probes is in sduprobes.c; this routine
is built with debugging turned on and is in the library libsduprobes.a.
The goal, ultimately, is for this to be a shared library.  There can be
a many to one relationship between the STAP_PROBEN probes and the
landing pad, so a .probes section is created which stap uses to
determine the proper corresponding  probe point.  For example there may
be multiple uses of STAP_PROBE2, which uses stap_probe_2 as a landing
pad.  The .probes section is a list of the probe labels and the number
of arguments corresponding to that probe.  Running the application
without probling should have little or no impact.  Currently the support
for this is somewhat minimal.  The probes are defined using
__builtin_expect but a test is executed and a call is present.  The
__builtin_expect checks a sentinel value that is currently set via
setting the environment variable SYSTEMTAP_SDUPROBES.  It is desirable
to have stap be able to turn this off and on without the use of an
environment variable.
diff --git a/ChangeLog b/ChangeLog
index e37549d..ef10759 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-11-11  Stan Cox  <scox@redhat.com>
+
+	* Makefile.am (pkglib_LIBRARIES): New.
+	* stapprobes.5.in (process.mark): New.
+	* tapsets.cxx (register_patterns):  Add process.mark.
+	(dwarf_builder::build): Likewise.
+
 2008-11-06  Wenji Huang  <wenji.huang@oracle.com>
 
 	PR 6998
diff --git a/Makefile.am b/Makefile.am
index 0b21231..b603718 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,6 +87,9 @@ stamp-elfutils: config.status
 stap_DEPENDENCIES = lib-elfutils/libdw.so
 lib-elfutils/libdw.so: stamp-elfutils ;
 
+pkglib_LIBRARIES = libsduprobes.a
+libsduprobes_a_SOURCES = sduprobes.c
+
 PHONIES += install-elfutils
 install-elfutils:
 	mkdir -p $(DESTDIR)$(pkglibdir)
diff --git a/runtime/sduprobes.c b/runtime/sduprobes.c
new file mode 100644
index 0000000..4bee3bd
--- /dev/null
+++ b/runtime/sduprobes.c
@@ -0,0 +1,69 @@
+// Copyright (C) 2005-2008 Red Hat Inc.
+// Copyright (C) 2006 Intel Corporation.
+//
+// This file is part of systemtap, and is free software.  You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#include <stddef.h>
+#define unused __attribute__ ((unused))
+
+int _stap_probe_sentinel = 0;
+
+void
+_stap_probe_start()
+{
+   _stap_probe_sentinel = 1;
+}
+
+int
+_stap_probe_0 (char* probe unused)
+{
+   return 1;
+}
+
+int
+_stap_probe_1 (char* probe unused,
+	       size_t arg1 unused)
+{
+   return 1;
+}
+
+int
+_stap_probe_2 (char* probe unused ,
+	       size_t arg1 unused,
+	       size_t arg2 unused)
+{
+   return 1;
+}
+
+int
+_stap_probe_3 (char* probe unused,
+	       size_t arg1 unused,
+	       size_t arg2 unused,
+	       size_t arg3 unused)
+{
+   return 1;
+}
+
+int
+_stap_probe_4 (char* probe unused,
+	       size_t arg1 unused,
+	       size_t arg2 unused,
+	       size_t arg3 unused,
+	       size_t arg4 unused)
+{
+   return 1;
+}
+
+int
+_stap_probe_5 (char* probe unused,
+	       size_t arg1 unused,
+	       size_t arg2 unused,
+	       size_t arg3 unused,
+	       size_t arg4 unused,
+	       size_t arg5 unused)
+{
+   return 1;
+}
diff --git a/runtime/sduprobes.h b/runtime/sduprobes.h
new file mode 100644
index 0000000..b2c32e4
--- /dev/null
+++ b/runtime/sduprobes.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2005-2008 Red Hat Inc.
+// Copyright (C) 2006 Intel Corporation.
+//
+// This file is part of systemtap, and is free software.  You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#include <stdlib.h>
+#include <string.h>
+extern int _stap_probe_sentinel;
+
+#define STAP_PROBE_START()		      \
+  char *stap_sdt = getenv("SYSTEMTAP_SDT"); \
+  if (stap_sdt != NULL)		\
+     _stap_probe_start ()
+
+#define STAP_PROBE_STRUCT(probe,argc) \
+struct _probe_ ## probe  \
+{				 \
+  char probe_name [strlen(#probe)+1]; \
+  int arg_count;		 \
+}; \
+static volatile struct _probe_ ## probe _probe_ ## probe __attribute__ ((section (".probes"))) = {#probe,argc};
+
+#define STAP_PROBE(provider,probe) \
+STAP_PROBE_STRUCT(probe,0)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_0 (_probe_ ## probe.probe_name);
+
+
+#define STAP_PROBE1(provider,probe,arg1) \
+STAP_PROBE_STRUCT(probe,1)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_1 (_probe_ ## probe.probe_name,(size_t)arg1);
+
+
+#define STAP_PROBE2(provider,probe,arg1,arg2) \
+STAP_PROBE_STRUCT(probe,2)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_2 (_probe_ ## probe.probe_name,(size_t)arg1,(size_t)arg2);
+
+#define STAP_PROBE3(provider,probe,arg1,arg2,arg3) \
+STAP_PROBE_STRUCT(probe,3)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_3 (_probe_ ## probe.probe_name,(size_t)arg1,(size_t)arg2,(size_t)arg3);
+
+#define STAP_PROBE4(provider,probe,arg1,arg2,arg3,arg4)	\
+STAP_PROBE_STRUCT(probe,4)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_4 (_probe_ ## probe.probe_name,(size_t)arg1,(size_t)arg2,(size_t)arg3,(size_t)arg4);
+
+#define STAP_PROBE5(provider,probe,arg1,arg2,arg3,arg4,arg5)	\
+STAP_PROBE_STRUCT(probe,5)	   \
+  if (__builtin_expect(_stap_probe_sentinel, 0)) \
+    _stap_probe_5 (_probe_ ## probe.probe_name,(size_t)arg1,(size_t)arg2,(size_t)arg3,(size_t)arg4,(size_t)arg5);
diff --git a/stapprobes.5.in b/stapprobes.5.in
index 36b3615..8ff33ce 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -404,6 +404,7 @@ process("PATH").syscall.return
 process.syscall.return
 process(PID).itrace
 process("PATH").itrace
+process("PATH").mark("LABEL")
 .ESAMPLE
 .PP
 A
@@ -439,6 +440,15 @@ context variable.
 A
 .B .itrace
 probe gets called for every single step of the process described by PID or PATH.
+A
+.B .mark
+probe gets called via a static probe defined in advance in the process
+described by PATH.  The probe is defined by
+STAP_PROBE1(handle,LABEL,arg1).  The handle is an application handle,
+LABEL corresponds to the .mark argument, and arg1 is the argument.
+STAP_PROBE1 is used for probes with 1 argument, STAP_PROBE2 is used
+for probes with 2 arguments, and so on.
+The arguments of the probe are available in the context variables $arg1, $arg2, ...
 .PP
 Note that
 .I PATH
diff --git a/tapsets.cxx b/tapsets.cxx
index 8d371a8..6920a97 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -460,6 +460,7 @@ static string TOK_MAXACTIVE("maxactive");
 static string TOK_STATEMENT("statement");
 static string TOK_ABSOLUTE("absolute");
 static string TOK_PROCESS("process");
+static string TOK_MARK("mark");
 
 // Can we handle this query with just symbol-table info?
 enum dbinfo_reqt
@@ -976,6 +977,9 @@ struct dwflpp
                    string(" debuginfo"),
                    mod);
 
+    if (!module)
+      module = mod;
+
     // NB: the result of an _offline call is the assignment of
     // virtualized addresses to relocatable objects such as
     // modules.  These have to be converted to real addresses at
@@ -4856,6 +4860,8 @@ dwarf_derived_probe::register_patterns(match_node * root)
   root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw);
 
   register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw);
+  root->bind_str(TOK_PROCESS)->bind_str(TOK_MARK)->bind(dw);
+  root->bind_str(TOK_PROCESS)->bind_num(TOK_MARK)->bind(dw);
 }
 
 void
@@ -5186,6 +5192,47 @@ dwarf_builder::build(systemtap_session & sess,
   if (! sess.module_cache)
     sess.module_cache = new module_cache ();
 
+  if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK)
+  {
+    // Generate: _probe_string = user_string($probe);
+    block *b = ((block*)(base->body));
+    assignment *as = new assignment;
+    symbol* lsym = new symbol;
+    lsym->type = pe_string;
+    lsym->name = "_probe_string";
+    lsym->tok = base->body->tok;
+    as->left = lsym;
+    as->op = "=";
+    functioncall *fc = new functioncall;
+    fc->function = "user_string";
+    fc->tok = base->body->tok;
+    target_symbol* rsym = new target_symbol;
+    rsym->base_name = "$probe";
+    rsym->tok = base->body->tok;
+    fc->args.push_back(rsym);
+    as->right = fc;
+    expr_statement* es = new expr_statement;
+    es->value = as;
+
+    // Generate: if (_probe_string == mark("label")) next;
+    if_statement *is = new if_statement;
+    is->thenblock = new next_statement;
+    is->elseblock = NULL;
+    is->tok = base->body->tok;
+    comparison *be = new comparison;
+    be->op = "!=";
+    be->tok = base->body->tok;
+    be->left = lsym;
+    be->right = new literal_string(location->components[1]->arg->tok->content);;
+    is->condition = be;
+
+    b->statements.insert(b->statements.begin(),(statement*) is);
+    b->statements.insert(b->statements.begin(),(statement*) es);
+
+    location->components[0]->arg = new literal_string(sess.cmd);
+    ((literal_map_t&)parameters)[location->components[0]->functor] = location->components[0]->arg;
+  }
+
   string module_name;
   if (has_null_param (parameters, TOK_KERNEL)
       || get_param (parameters, TOK_MODULE, module_name))
@@ -5216,6 +5263,62 @@ dwarf_builder::build(systemtap_session & sess,
         dw = user_dw[module_name];
     }
 
+  if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK)
+    {
+      Dwarf_Addr bias;
+      Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias))
+                  ?: dwfl_module_getelf (dw->module, &bias));
+      size_t shstrndx;
+
+      Elf_Scn *probe_scn = NULL;
+      dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
+      int argc = 0;
+      // Find the .probes section where the static probe label and arg count are stored
+      while ((probe_scn = elf_nextscn (elf, probe_scn)))
+        {
+          GElf_Shdr shdr_mem;
+          GElf_Shdr *shdr = gelf_getshdr (probe_scn, &shdr_mem);
+          assert (shdr != NULL);
+
+          if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name), ".probes") != 0)
+            continue;
+          Elf_Data *pdata = elf_getdata (probe_scn, NULL);
+          assert (pdata != NULL);
+          size_t probe_scn_offset = 0;
+          while (probe_scn_offset < pdata->d_size)
+            {
+              char *probe_name = (char*)pdata->d_buf + probe_scn_offset;
+              probe_scn_offset += strlen(probe_name);
+              probe_scn_offset += 4 - (probe_scn_offset % 4);
+              argc = *(((char*)pdata->d_buf + probe_scn_offset));
+              probe_scn_offset += sizeof(int);
+              if (strcmp (location->components[1]->arg->tok->content.c_str(), probe_name) == 0)
+                break;
+            }
+        }
+
+      Dwarf *dwarf = dwfl_module_getdwarf(dw->module, &dw->module_bias);
+      Dwarf_Off off;
+      size_t cuhl;
+      Dwarf_Off noff = 0;
+      const char *probe_cudie = "";
+      // Find where the probe instrumentation landing points are defined
+      while (dwarf_nextcu (dwarf, off = noff, &noff, &cuhl, NULL, NULL, NULL) == 0)
+        {
+          Dwarf_Die cudie_mem;
+          Dwarf_Die *cudie = dwarf_offdie (dwarf, off + cuhl, &cudie_mem);
+          if (cudie == NULL)
+            continue;
+          if (strncmp (dwarf_diename(&cudie_mem), "stap-probes", 11) == 0)
+            probe_cudie = dwarf_diename(&cudie_mem);
+        }
+      location->components[1]->functor = TOK_STATEMENT;
+      string argc_str = string(1,'0' + argc);
+      location->components[1]->arg = new literal_string("_stap_probe_" + (argc_str)
+          + "@" + probe_cudie + "+1");
+      ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg;
+      dw->module = 0;
+    }
 
   dwarf_query q(sess, base, location, *dw, parameters, finished_results);
 
@@ -7926,7 +8029,6 @@ procfs_builder::build(systemtap_session & sess,
 // statically inserted macro-based derived probes
 // ------------------------------------------------------------------------
 
-static string TOK_MARK("mark");
 static string TOK_FORMAT("format");
 
 struct mark_arg
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index d0a3a4f..d4ed71a 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2008-11-11  Stan Cox  <scox@redhat.com>
+
+	* systemtap.base/sduprobes.c: New file.
+	* systemtap.base/sduprobes.exp: New file.
+	* systemtap.base/sduprobes.stp: New file.
+
 2008-11-03  Wenji Huang  <wenji.huang@oracle.com>
 
 	* systemtap.base/cmd_parse.exp: Add exit() to probe.
diff --git a/testsuite/systemtap.base/sduprobes.c b/testsuite/systemtap.base/sduprobes.c
new file mode 100644
index 0000000..1506107
--- /dev/null
+++ b/testsuite/systemtap.base/sduprobes.c
@@ -0,0 +1,33 @@
+#include "sduprobes.h"
+
+foo ()
+{
+  STAP_PROBE(tstlabel,label1);
+}
+
+bar (int i)
+{
+  if (i == 0)
+    i = 1000;
+  STAP_PROBE1(tstlabel,label2,i);
+}
+
+baz (int i, char* s)
+{
+  if (i == 0)
+    i = 1000;
+  STAP_PROBE2(tstlabel,label3,i,s);
+}
+
+buz ()
+{
+}
+
+main ()
+{
+  sleep(5);
+  STAP_PROBE_START();
+  foo();
+  bar(2);
+  baz(3,"abc");
+}
diff --git a/testsuite/systemtap.base/sduprobes.exp b/testsuite/systemtap.base/sduprobes.exp
new file mode 100644
index 0000000..cd1656a
--- /dev/null
+++ b/testsuite/systemtap.base/sduprobes.exp
@@ -0,0 +1,14 @@
+# Compile our test program.
+set sduprobes_srcpath "$srcdir/systemtap.base/sduprobes.c"
+set sduprobes_exepath "[pwd]/sduprobes_[pid]"
+set sduprobes_flags "additional_flags=-iquote$env(SYSTEMTAP_RUNTIME) additional_flags=-L$env(SYSTEMTAP_PATH) additional_flags=-lsduprobes"
+puts $sduprobes_flags
+
+set res [target_compile $sduprobes_srcpath $sduprobes_exepath executable $sduprobes_flags]
+if { $res != "" } {
+    verbose "target_compile failed: $res" 2
+    fail "unable to compile $sduprobes_srcpath"
+    return
+} else {
+    pass "compiling $sduprobes_srcpath" 
+}
diff --git a/testsuite/systemtap.base/sduprobes.stp b/testsuite/systemtap.base/sduprobes.stp
new file mode 100644
index 0000000..e78013f
--- /dev/null
+++ b/testsuite/systemtap.base/sduprobes.stp
@@ -0,0 +1,14 @@
+probe process.mark("label1") 
+{ 
+printf("In label1 probe\n",)
+}
+
+probe process.mark("label2") 
+{ 
+printf("In label2 probe %#x\n", $arg1)
+}
+
+probe process.mark("label3") 
+{ 
+printf("In label3 probe %#x %#x\n", $arg1, $arg2)
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]