From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7206 invoked by alias); 12 Nov 2008 03:40:57 -0000 Received: (qmail 7072 invoked by uid 22791); 12 Nov 2008 03:40:54 -0000 X-Spam-Status: No, hits=-1.0 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_14,J_CHICKENPOX_66,J_CHICKENPOX_73,J_CHICKENPOX_74,KAM_MX,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 12 Nov 2008 03:40:07 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id mAC3e55p024670 for ; Tue, 11 Nov 2008 22:40:05 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id mAC3e4Vn028517 for ; Tue, 11 Nov 2008 22:40:04 -0500 Received: from [10.11.228.43] (multics.rdu.redhat.com [10.11.228.43]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id mAC3e3Ig014185 for ; Tue, 11 Nov 2008 22:40:03 -0500 Subject: static defined user probes From: Stan Cox To: systemtap@sources.redhat.com Content-Type: multipart/mixed; boundary="=-DM0De1JkfuytXrBkpVk4" Date: Wed, 12 Nov 2008 03:40:00 -0000 Message-Id: <1226461203.3767.116.camel@multics.rdu.redhat.com> Mime-Version: 1.0 X-Scanned-By: MIMEDefang 2.58 on 172.16.52.254 X-Virus-Checked: Checked by ClamAV on sourceware.org X-IsSubscribed: yes Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org X-SW-Source: 2008-q4/txt/msg00329.txt.bz2 --=-DM0De1JkfuytXrBkpVk4 Content-Type: text/plain Content-Transfer-Encoding: 7bit Content-length: 1623 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. --=-DM0De1JkfuytXrBkpVk4 Content-Disposition: attachment; filename=sduprobes.patch Content-Type: text/x-patch; name=sduprobes.patch; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-length: 13463 diff --git a/ChangeLog b/ChangeLog index e37549d..ef10759 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-11-11 Stan Cox + + * 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 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 +#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 +#include +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 + + * systemtap.base/sduprobes.c: New file. + * systemtap.base/sduprobes.exp: New file. + * systemtap.base/sduprobes.stp: New file. + 2008-11-03 Wenji Huang * 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) +} --=-DM0De1JkfuytXrBkpVk4--