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) +}