From 1560c9c96e666c7e5893f2c20ed12c0ddd7cb600 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Sep 2007 14:41:00 -0400 Subject: remove problematic $target variable from signal.send 2007-09-25 Frank Ch. Eigler * signal.stp (_signal.send.part*): Remove sinfo alias variable, since it's a struct rather than integral value. --- tapset/ChangeLog | 5 +++++ tapset/signal.stp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 5d70d2c5..feabc0bf 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,8 @@ +2007-09-25 Frank Ch. Eigler + + * signal.stp (_signal.send.part*): Remove sinfo alias variable, + since it's a struct rather than integral value. + 2007-09-25 Martin Hunt * syscalls2.stp (sys_readlinkat): Make optional. diff --git a/tapset/signal.stp b/tapset/signal.stp index e1171c5a..95ead176 100644 --- a/tapset/signal.stp +++ b/tapset/signal.stp @@ -62,7 +62,7 @@ probe _signal.send.part2 = kernel.function("send_group_sigqueue") { name = "send_group_sigqueue" task = $p - sinfo = $q->info + # sinfo = $q->info shared = 1 send2queue = 1 } @@ -71,7 +71,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue") { name = "send_sigqueue" task = $p - sinfo = $q->info + # sinfo = $q->info shared = 0 send2queue = 1 } -- cgit From eab72760b4ec098647a24d4095966699796da377 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Sep 2007 15:22:09 -0400 Subject: * build fix on rhel4 2007-09-25 Frank Ch. Eigler * socket.stp (__i2n_ip_proto): Add a cast for 32-bit compatibility. --- tapset/ChangeLog | 4 ++++ tapset/nfs_proc.stp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index feabc0bf..5cd5a6d5 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,7 @@ +2007-09-25 Frank Ch. Eigler + + * socket.stp (__i2n_ip_proto): Add a cast for 32-bit compatibility. + 2007-09-25 Frank Ch. Eigler * signal.stp (_signal.send.part*): Remove sinfo alias variable, diff --git a/tapset/nfs_proc.stp b/tapset/nfs_proc.stp index dd46544f..3ccd016b 100644 --- a/tapset/nfs_proc.stp +++ b/tapset/nfs_proc.stp @@ -41,7 +41,7 @@ */ function __i2n_ip_proto :long(dir:long,index:long) %{ /* pure */ int index = (int) (THIS->index); - struct inode * dir = (struct inode *)(THIS->dir); + struct inode * dir = (struct inode *)(uintptr_t)(THIS->dir); struct rpc_clnt * clnt = NFS_CLIENT(dir); /* FIXME: deref hazard! */ struct rpc_xprt * cl_xprt = kread(&(clnt->cl_xprt)); /* sockaddr_storage is used since 2.6.19. Need cast*/ -- cgit From d1802bc3d2059bb6baaea88bf5976c98420ba4f3 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Sep 2007 15:30:42 -0400 Subject: socket.stp build fix for 2.6.9 kernel 2007-09-25 Frank Ch. Eigler * socket.stp (sock_flags_num2str): Define SOCK_PASSCRED if needed. --- tapset/ChangeLog | 4 ++++ tapset/socket.stp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 5cd5a6d5..48b6b86e 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,7 @@ +2007-09-25 Frank Ch. Eigler + + * socket.stp (sock_flags_num2str): Define SOCK_PASSCRED if needed. + 2007-09-25 Frank Ch. Eigler * socket.stp (__i2n_ip_proto): Add a cast for 32-bit compatibility. diff --git a/tapset/socket.stp b/tapset/socket.stp index 563b866b..fc532b1d 100644 --- a/tapset/socket.stp +++ b/tapset/socket.stp @@ -626,6 +626,9 @@ function sock_type_str2num:long (type:string) function sock_flags_num2str:string (flags:long) %{ /* pure */ +#ifndef SOCK_PASSCRED +#define SOCK_PASSCRED 3 /* introduced in 2.6.12? */ +#endif #ifndef SOCK_PASSSEC #define SOCK_PASSSEC 4 /* introduced in 2.6.18 */ #endif -- cgit From b494502e57c78a71c93d25291ff592bfc9f2d2d7 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Sep 2007 15:31:18 -0400 Subject: typo fix --- tapset/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 48b6b86e..a1cf0132 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -4,7 +4,7 @@ 2007-09-25 Frank Ch. Eigler - * socket.stp (__i2n_ip_proto): Add a cast for 32-bit compatibility. + * nfs_proc.stp (__i2n_ip_proto): Add a cast for 32-bit compatibility. 2007-09-25 Frank Ch. Eigler -- cgit From fe430a061dd22c3a2d30ccb55d28f7994b4d20c7 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 27 Sep 2007 13:36:24 -0400 Subject: grammar tweaks Signed-off-by: Randy Dunlap --- examples/small_demos/demo_script.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/small_demos/demo_script.txt b/examples/small_demos/demo_script.txt index 48d90c9c..f3166a49 100644 --- a/examples/small_demos/demo_script.txt +++ b/examples/small_demos/demo_script.txt @@ -1,12 +1,12 @@ > cd /root/systemtap -A systemtap script can be as simple as a simgle line. For example, -thge following script places a probepoint on the kernel sys_read() +A systemtap script can be as simple as a single line. For example, +the following script places a probepoint on the kernel sys_read() function and prints all callers with the function's arguments. >stap -e 'probe syscall.open {printf("%s: %s\n", execname(), argstr)}' -Most script are a bit longer. (show top.stp) +Most scripts are a bit longer. (show top.stp) This script sets a probepoint on all kernel functions beginning with "sys_". When the probepoint is hit, it increments an entry in the map (or associative array) "syscalls" with the key "probefunc()" which returns @@ -25,24 +25,24 @@ while it is loading.) The "top" script looked only at the functions called. If we want more detail about the functions, we can use systemtap to examine their local arguments and variables. However that would be difficult because each -system call has different parameters. The Sycall Tapset solves +system call has different parameters. The Syscall Tapset solves this problem. To use it, we set probe points using the syntax "syscall.name" instead of kernel.function("sys_name"). The Syscall Tapset provides three -defined variables we can use, +defined variables we can use: name - the name of the function argstr - on function entry, a formatted string containing the arguments retstr - on function exit, the return value and possibly error code In this example, we filter out programs named "staprun" because this is part of the systemtap infrastructure. (It may be filtered out -automatically in the future) +automatically in the future.) -The next example shows how you can use systemtap to focus on +The next example shows how you can use systemtap to focus on specific programs or pids. (show prof.stp) Like the "top" example, this script places probes on all kernel functions starting with "sys_". Only the probepoint also checks to see -if the tid/pid matches the one returned by "target()" We'll show how +if the tid/pid matches the one returned by "target()". We'll show how the target pid is set later. Unlike the previous examples, this script sets a probe point on all the @@ -100,4 +100,3 @@ program name. The output might be large so we'll redirect it to a file. > more out - -- cgit From fe2c47600872986cd9278f2baa6136261ea4fb0c Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 28 Sep 2007 21:07:27 -0400 Subject: * Makefile.in: Regenerated from Jim Keniston's uprobes Makefile.am changes. --- AUTHORS | 1 + ChangeLog | 5 +++++ Makefile.in | 9 +++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 05f0940e..a0a551fc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,6 +4,7 @@ Li Guanglei Joshua Stone David Smith Graydon Hoare +Jim Keniston Roland McGrath Will Cohen Thang Nguyen diff --git a/ChangeLog b/ChangeLog index 2fd88a5e..a855e857 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-09-28 Frank Ch. Eigler + + * Makefile.in: Regenerated from Jim Keniston's uprobes Makefile.am + changes. + 2007-09-25 Josh Stone * tapsets.cxx (translator_output::~translator_output): Fix mismatched diff --git a/Makefile.in b/Makefile.in index 2653d505..47509606 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,7 +61,7 @@ DIST_COMMON = README $(am__configure_deps) $(dist_man_MANS) \ $(top_srcdir)/man/stapprobes.tcp.5.in \ $(top_srcdir)/man/stapprobes.udp.5.in AUTHORS COPYING \ ChangeLog INSTALL NEWS compile config.guess depcomp install-sh \ - ltmain.sh missing + missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -147,7 +147,7 @@ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = testsuite +DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -196,7 +196,6 @@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ -MYSQL_CONFIG = @MYSQL_CONFIG@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -320,7 +319,7 @@ SAMPLE_SRC = $(srcdir)/testsuite/systemtap.samples/iotask.stp \ TEST_COV_DIR = coverage # XXX: leaves behind man pages -SUBDIRS = testsuite $(am__append_4) +SUBDIRS = testsuite all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -1496,6 +1495,8 @@ install-data-local: (cd $(srcdir)/runtime; for f in *.[ch]; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/$$f; done) (cd $(srcdir)/runtime/transport; for f in *.[ch]; \ do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/transport/$$f; done) + (cd $(srcdir)/runtime/uprobes; for f in *.[ch]; \ + do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/uprobes/$$f; done) (cd $(srcdir)/tapset; find . \( -name '*.stp' -o -name README \) -print \ | while read f; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/tapset/$$f; done) -- cgit From 7e01de25b1ac1ae337d7c322911b7eefdfc096cd Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Wed, 3 Oct 2007 16:33:47 -0400 Subject: PR 5096: improve code generation for function calls 2007-10-03 Frank Ch. Eigler PR 5096 * translate.cxx (emit_function): Put nesting limit/control logic into function body ... (visit_functioncall): ... and not into each call site. --- ChangeLog | 7 +++++++ translate.cxx | 37 +++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26a55d74..4142933c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2007-10-03 Frank Ch. Eigler + + PR 5096 + * translate.cxx (emit_function): Put nesting limit/control logic into + function body ... + (visit_functioncall): ... and not into each call site. + 2007-10-02 Frank Ch. Eigler PR 3635 diff --git a/translate.cxx b/translate.cxx index 8e24fca0..578bbc37 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1333,13 +1333,21 @@ c_unparser::emit_function (functiondecl* v) << "struct function_" << c_varname (v->name) << "_locals * " << " __restrict__ l ="; o->newline(1) - << "& c->locals[c->nesting].function_" << c_varname (v->name) + << "& c->locals[c->nesting+1].function_" << c_varname (v->name) // NB: nesting+1 << ";"; o->newline(-1) << "(void) l;"; // make sure "l" is marked used o->newline() << "#define CONTEXT c"; o->newline() << "#define THIS l"; o->newline() << "if (0) goto out;"; // make sure out: is marked used + // check/increment nesting level + o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {"; + o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; + o->newline() << "return;"; + o->newline(-1) << "} else {"; + o->newline(1) << "c->nesting ++;"; + o->newline(-1) << "}"; + // initialize locals // XXX: optimization: use memset instead for (unsigned i=0; ilocals.size(); i++) @@ -1358,13 +1366,23 @@ c_unparser::emit_function (functiondecl* v) o->newline() << retvalue.init(); } + o->newline() << "#define return goto out"; // redirect embedded-C return v->body->visit (this); + o->newline() << "#undef return"; this->current_function = 0; o->newline(-1) << "out:"; o->newline(1) << ";"; + // Function prologue: this is why we redirect the "return" above. + // Decrement nesting level. + o->newline() << "c->nesting --;"; + // Reset last_error to NULL if it was set to "" by script-level return() + o->newline() << "if (c->last_error && ! c->last_error[0])"; + o->newline(1) << "c->last_error = 0;"; + o->indent(-1); + o->newline() << "#undef CONTEXT"; o->newline() << "#undef THIS"; o->newline(-1) << "}\n"; @@ -3878,13 +3896,6 @@ c_unparser::visit_functioncall (functioncall* e) tmp.push_back(t); } - o->newline(); - o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {"; - o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; - o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; - o->newline(-1) << "} else if (likely (! c->last_error)) {"; - o->indent(1); - // copy in actual arguments for (unsigned i=0; iargs.size(); i++) { @@ -3902,19 +3913,9 @@ c_unparser::visit_functioncall (functioncall* e) } // call function - o->newline() << "c->nesting ++;"; o->newline() << "function_" << c_varname (r->name) << " (c);"; - o->newline() << "c->nesting --;"; - - // reset last_error to NULL if it was set to "" by return() - o->newline() << "if (c->last_error && ! c->last_error[0])"; - o->newline(1) << "c->last_error = 0;"; - o->indent(-1); - - o->newline(-1) << "}"; // return result from retvalue slot - if (r->type == pe_unknown) // If we passed typechecking, then nothing will use this return value o->newline() << "(void) 0;"; -- cgit From 87ca0f3761f70d2b3db8e4d8a7b293d1ca159f8a Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Wed, 3 Oct 2007 18:24:28 -0400 Subject: testsuite verbosity cleanup 2007-10-03 Frank Ch. Eigler * systemtap.syscall/test.tcl: Don't list PASS on stdout. --- testsuite/ChangeLog | 6 +++++- testsuite/systemtap.syscall/test.tcl | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 270b2caf..dc638be2 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-10-03 Frank Ch. Eigler + + * systemtap.syscall/test.tcl: Don't list PASS on stdout. + 2007-10-02 Frank Ch. Eigler PR 5078 @@ -11,7 +15,7 @@ 2007-09-28 Wenji Huang - * lib/systemtap.exp: New proc get_system_info. + * lib/systemtap.exp: New proc get_system_info. * lib/stap_run.exp: New proc print_system_info. 2007-09-27 Masami Hiramatsu diff --git a/testsuite/systemtap.syscall/test.tcl b/testsuite/systemtap.syscall/test.tcl index 21db59fd..a3ac7f49 100755 --- a/testsuite/systemtap.syscall/test.tcl +++ b/testsuite/systemtap.syscall/test.tcl @@ -85,7 +85,7 @@ proc run_one_test {filename flags} { } if {$i >= $ind} { set result "PASS" - puts "PASS $testname" + # puts "PASS $testname" } else { set result "FAIL $testname" send_log "$testname FAILED. output of \"$cmd\" was:" -- cgit From e4bc17d6daed552fab9fc657321e30c260e43fe2 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 11 Oct 2007 17:56:14 -0400 Subject: * specfile dep fix 2007-10-11 Frank Ch. Eigler * systemtap.spec.in: Make -testsuite subrpm require dejagnu. --- ChangeLog | 4 ++++ systemtap.spec.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 77883fc6..9b68930a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-10-11 Frank Ch. Eigler + + * systemtap.spec.in: Make -testsuite subrpm require dejagnu. + 2007-10-10 Jim Keniston * runtime/uprobes/uprobes_ppc64.[ch]: Added diff --git a/systemtap.spec.in b/systemtap.spec.in index aeb8f99a..bbb9526c 100644 --- a/systemtap.spec.in +++ b/systemtap.spec.in @@ -90,7 +90,7 @@ Summary: Instrumentation System Testsuite Group: Development/System License: GPLv2+ URL: http://sourceware.org/systemtap/ -Requires: systemtap +Requires: systemtap dejagnu %description testsuite The testsuite allows testing of the entire SystemTap toolchain -- cgit From fa580cd019b38eaaeb3d694ace982da9ebcce294 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 11 Oct 2007 21:50:44 -0400 Subject: * staprun error-check reordering for parseko/cmdline* tests * staprun.c (main): Move checks for init_cap and getuid from just before command line argument parsing to just after. --- runtime/staprun/ChangeLog | 5 +++++ runtime/staprun/staprun.c | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index 4e23c424..2a9029d0 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,8 @@ +2007-10-11 Frank Ch. Eigler + + * staprun.c (main): Move checks for init_cap and getuid + from just before command line argument parsing to just after. + 2007-10-09 Martin Hunt * common.c (set_clexec): New. diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 67b01abb..44ac0313 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -211,15 +211,8 @@ int main(int argc, char **argv) exit(1); } - if (geteuid() != 0) { - err("ERROR: The effective user ID of staprun must be set to the root user.\n" - " Check permissions on staprun and ensure it is a setuid root program.\n"); - exit(1); - } - - if (!init_cap()) - exit(1); - + /* NB: Don't do the geteuid()!=0 check here, since we want to + test command-line error-handling while running non-root. */ /* Get rid of a few standard environment variables (which */ /* might cause us to do unintended things). */ rc = unsetenv("IFS") || unsetenv("CDPATH") || unsetenv("ENV") @@ -258,6 +251,15 @@ int main(int argc, char **argv) usage(argv[0]); } + if (geteuid() != 0) { + err("ERROR: The effective user ID of staprun must be set to the root user.\n" + " Check permissions on staprun and ensure it is a setuid root program.\n"); + exit(1); + } + + if (!init_cap()) + exit(1); + if (check_permissions() != 1) usage(argv[0]); -- cgit From 51bf59c154c1dd2d4e681d8eb6c916c73af3b476 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 26 Nov 2007 10:11:18 -0500 Subject: * conditional-probe SEGV fix 2007-11-26 Frank Ch. Eigler * elaborate.cxx (derived_probe ctor): Don't duplicate condition if it doesn't exist. --- ChangeLog | 5 +++++ elaborate.cxx | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 83e56786..c3ce7926 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2007-11-26 Frank Ch. Eigler + + * elaborate.cxx (derived_probe ctor): Don't duplicate condition + if it doesn't exist. + 2007-11-20 Masami Hiramatsu PR 4935. diff --git a/elaborate.cxx b/elaborate.cxx index d3bbe28d..c277d8d5 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -53,7 +53,8 @@ derived_probe::derived_probe (probe *p, probe_point *l): { if (p) { - this->condition = deep_copy_visitor::deep_copy(p->condition); + if (p->condition) + this->condition = deep_copy_visitor::deep_copy(p->condition); this->tok = p->tok; this->privileged = p->privileged; this->body = deep_copy_visitor::deep_copy(p->body); -- cgit From ea6507e4e059aa8897118aff91e1910372c74c02 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 26 Nov 2007 10:46:21 -0500 Subject: * conditional probe thinko fix cont'd --- ChangeLog | 1 + staptree.cxx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index c3ce7926..cde76f43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ * elaborate.cxx (derived_probe ctor): Don't duplicate condition if it doesn't exist. + * staptree.cxx (probe_point, probe ctors): Initialize to 0. 2007-11-20 Masami Hiramatsu diff --git a/staptree.cxx b/staptree.cxx index 42fc8c24..d0b4a0ed 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -76,19 +76,19 @@ symboldecl::~symboldecl () probe_point::probe_point (std::vector const & comps, const token * t): components(comps), tok(t), optional (false), sufficient (false), - condition (NULL) + condition (0) { } probe_point::probe_point (): - tok (0), optional (false), sufficient (false), condition (NULL) + tok (0), optional (false), sufficient (false), condition (0) { } unsigned probe::last_probeidx = 0; probe::probe (): - body (0), tok (0) + body (0), tok (0), condition (0) { this->name = string ("probe_") + lex_cast(last_probeidx ++); } -- cgit From 95a664e8c311ba02b7e6f20eb8695b37765ed39a Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 30 Nov 2007 18:59:34 -0500 Subject: PR5438: document libcap-devel build-time dependency From Julio M. Merino Vidal : Include libcap-devel in named build dependencies (for ). --- README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index a4790ccc..0ea30508 100644 --- a/README +++ b/README @@ -25,9 +25,9 @@ Installation steps: Build steps: -- Install the kernel-debuginfo, kernel-[smp-]devel, gcc packages - (or see below if you are building your own kernels from source). -- Download the latest elfutils snapshot: +- Install the kernel-debuginfo, kernel-[smp-]devel, gcc and libcap-devel + packages (or see below if you are building your own kernels from source). +- Download the latest elfutils snapshot (if desired): ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-NNNN.tar.gz ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-portability.patch - Untar the snapshot in some new directory; apply patch (don't ask, long story) @@ -44,7 +44,7 @@ Build steps: cd src ./configure --with-elfutils=PATCHED-ELFUTILS-DIR [other autoconf options] make all check - make install + sudo make install Tips: -- cgit From 18e70d579158bef907110277239c81845a11e927 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Wed, 2 Jan 2008 13:22:01 -0500 Subject: Fix mkdtemp() umask issue Even though the mkdtemp() man page indicates that the directory will be created with always 0700 permissions, it is actually affected by the process's umask. So, if you run stap with an unusual umask it can end up creating the temp dir with permissions that staprun can't handle e.g.: $> rpm -q systemtap systemtap-0.6-1.fc9 $> umask 0122 $> stap -e 'probe begin { println("foo") exit() }' ERROR: Error opening '/tmp/stapV4pBIb/stap_725b9bc541cef2618a5ccbc58bb64d15_287.ko': Permission denied Obvious solution is to briefly set the umask to zero in stap so as to ensure 0700 permissions. Signed-off-by: Mark McLoughlin --- main.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.cxx b/main.cxx index 1880436f..556b30ff 100644 --- a/main.cxx +++ b/main.cxx @@ -521,7 +521,9 @@ main (int argc, char * const argv []) string stapdir = "/stapXXXXXX"; string tmpdirt = tmpdir_env + stapdir; + mode_t mask = umask(0); const char* tmpdir = mkdtemp((char *)tmpdirt.c_str()); + umask(mask); if (! tmpdir) { const char* e = strerror (errno); -- cgit From 5ccae5495728321f4fcb22353cefe42204f3250b Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 12 Jan 2008 22:05:47 -0500 Subject: add git commit id as testsuite Snapshot field 2008-01-12 Frank Ch. Eigler * configure.ac: Generate a build tree SNAPSHOT file from git-rev-list, if we suspect the source tree came from git. * configure: Regenerated. 2008-01-12 Frank Ch. Eigler * lib/systemtap.exp (get_system_info): Look for $builddir/SNAPSHOT too. --- ChangeLog | 6 ++++++ configure | 7 +++++++ configure.ac | 7 +++++++ testsuite/ChangeLog | 4 ++++ testsuite/lib/systemtap.exp | 4 +++- 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ab1a2fc5..28109604 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-01-12 Frank Ch. Eigler + + * configure.ac: Generate a build tree SNAPSHOT file from git-rev-list, + if we suspect the source tree came from git. + * configure: Regenerated. + 2008-01-12 Frank Ch. Eigler PR 5603. diff --git a/configure b/configure index ccca2d7f..1a547523 100755 --- a/configure +++ b/configure @@ -6572,6 +6572,13 @@ cap_LIBS="$LIBS" LIBS="$SAVE_LIBS" CFLAGS="$SAVE_CFLAGS" +if test -d $srcdir/.git -a ! -f $srcdir/SNAPSHOT; then + snapshot=`cd $srcdir; git-rev-list --abbrev-commit --max-count=1 HEAD` + echo $snapshot > SNAPSHOT + { echo "$as_me:$LINENO: Created git SNAPSHOT $snapshot" >&5 +echo "$as_me: Created git SNAPSHOT $snapshot" >&6;} +fi + ac_config_headers="$ac_config_headers config.h:config.in" ac_config_files="$ac_config_files Makefile systemtap.spec stap.1 stapprobes.5 stapfuncs.5 stapex.5 staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5" diff --git a/configure.ac b/configure.ac index 522af8d7..256155a8 100644 --- a/configure.ac +++ b/configure.ac @@ -161,6 +161,13 @@ AC_SUBST(cap_LIBS) LIBS="$SAVE_LIBS" CFLAGS="$SAVE_CFLAGS" +dnl Create SNAPSHOT file from git commit id if possible +if test -d $srcdir/.git -a ! -f $srcdir/SNAPSHOT; then + snapshot=`cd $srcdir; git-rev-list --abbrev-commit --max-count=1 HEAD` + echo $snapshot > SNAPSHOT + AC_MSG_NOTICE([Created git SNAPSHOT $snapshot]) +fi + AC_CONFIG_HEADERS([config.h:config.in]) AC_CONFIG_FILES(Makefile systemtap.spec stap.1 stapprobes.5 stapfuncs.5 stapex.5 staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5) AC_CONFIG_SUBDIRS(testsuite) diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index d8d26ce9..d8439450 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-01-12 Frank Ch. Eigler + + * lib/systemtap.exp (get_system_info): Look for $builddir/SNAPSHOT too. + 2008-01-09 Masami Hiramatsu PR5554 diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index 3b66b05a..f677da41 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -53,7 +53,9 @@ proc get_system_info {} { global Host Snapshot Distro env set Host [exec /bin/uname -a] - if [file exists $env(SRCDIR)/../SNAPSHOT] { + if [file exists ../SNAPSHOT] { + set Snapshot [exec /bin/cat ../SNAPSHOT] + } elseif [file exists $env(SRCDIR)/../SNAPSHOT] { set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT] } else { set Snapshot "unknown" -- cgit From 808462c906ccbab27dd05c16bd502a4dadcd2cfd Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 25 Jan 2008 14:04:39 -0500 Subject: PR 5672: fix generated dwarf probe point names from wildcards 2008-01-25 Frank Ch. Eigler PR 5672. * staptree.cxx (probe_point copy ctor): New function. * staptree.h: Declare it. * tapsets.cxx (dwarf_derived_probe ctor): Call it to shallow-copy incoming base probe location before recomputing/overwriting it. --- ChangeLog | 8 ++++++++ staptree.cxx | 8 ++++++++ staptree.h | 1 + tapsets.cxx | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6a2b8c27..3097675e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-01-25 Frank Ch. Eigler + + PR 5672. + * staptree.cxx (probe_point copy ctor): New function. + * staptree.h: Declare it. + * tapsets.cxx (dwarf_derived_probe ctor): Call it to shallow-copy + incoming base probe location before recomputing/overwriting it. + 2008-01-25 David Smith * configure.ac: Compressed the two perfmon options into one. diff --git a/staptree.cxx b/staptree.cxx index 173314ee..6d001375 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -82,6 +82,14 @@ probe_point::probe_point (std::vector const & comps, { } +// NB: shallow-copy of compoonents & condition! +probe_point::probe_point (const probe_point& pp): + components(pp.components), tok(pp.tok), optional (pp.optional), sufficient (pp.sufficient), + condition (pp.condition) +{ +} + + probe_point::probe_point (): tok (0), optional (false), sufficient (false), condition (0) { diff --git a/staptree.h b/staptree.h index 5b4b56cd..54194c7b 100644 --- a/staptree.h +++ b/staptree.h @@ -577,6 +577,7 @@ struct probe_point expression* condition; void print (std::ostream& o) const; probe_point (); + probe_point(const probe_point& pp); probe_point(std::vector const & comps,const token * t); std::string str(); }; diff --git a/tapsets.cxx b/tapsets.cxx index 06aa73aa..5b69373b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3635,7 +3635,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, Dwarf_Addr addr, dwarf_query& q, Dwarf_Die* scope_die /* may be null */) - : derived_probe (q.base_probe, q.base_loc /* NB: base_loc.components will be overwritten */ ), + : derived_probe (q.base_probe, new probe_point(*q.base_loc) /* .components soon rewritten */ ), module (module), section (section), addr (addr), has_return (q.has_return), has_maxactive (q.has_maxactive), -- cgit From 9a6524b486ecf0671b924a1c8b9d439a40810505 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 22 Feb 2008 21:10:14 -0500 Subject: PR5787, PR2608 --- buildrun.cxx | 2 +- tapsets.cxx | 111 ++++++++++++++++++++-------------- testsuite/systemtap.base/stmtvars.exp | 31 ++++++++++ 3 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 testsuite/systemtap.base/stmtvars.exp diff --git a/buildrun.cxx b/buildrun.cxx index 66cc4986..67836108 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -97,7 +97,7 @@ compile_pass (systemtap_session& s) for (unsigned i=0; i 2) + if (s.verbose > 3) o << "EXTRA_CFLAGS += -ftime-report -Q" << endl; // XXX: unfortunately, -save-temps can't work since linux kbuild cwd diff --git a/tapsets.cxx b/tapsets.cxx index e89cfe90..358478e6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2379,16 +2379,11 @@ dwarf_query::build_blacklist() // Add ^ anchors at the front; $ will be added just before regcomp. - // NB: all the regexp strings will start with "^(|foo|bar)$", note the - // empty first alternative. It's a bit unsightly, but it lets all the - // regexp concatenation statements look uniform, and we should have no - // empty actual strings to match against anyway. - string blfn = "^("; string blfn_ret = "^("; string blfile = "^("; - blfile += "|kernel/kprobes.c"; + blfile += "kernel/kprobes.c"; // first alternative, no "|" blfile += "|arch/.*/kernel/kprobes.c"; // XXX: it would be nice if these blacklisted functions were pulled @@ -2402,7 +2397,7 @@ dwarf_query::build_blacklist() // also allows detection of problems at translate- rather than // run-time. - blfn += "|atomic_notifier_call_chain"; + blfn += "atomic_notifier_call_chain"; // first blfn; no "|" blfn += "|default_do_nmi"; blfn += "|__die"; blfn += "|die_nmi"; @@ -2457,6 +2452,11 @@ dwarf_query::build_blacklist() blfn += "|.*preempt_count.*"; blfn += "|preempt_schedule"; + // These functions don't return, so return probes would never be recovered + blfn_ret += "do_exit"; // no "|" + blfn_ret += "|sys_exit"; + blfn_ret += "|sys_exit_group"; + // __switch_to changes "current" on x86_64 and i686, so return probes // would cause kernel panic, and it is marked as "__kprobes" on x86_64 if (sess.architecture == "x86_64") @@ -2464,15 +2464,18 @@ dwarf_query::build_blacklist() if (sess.architecture == "i686") blfn_ret += "|__switch_to"; - // These functions don't return, so return probes would never be recovered - blfn_ret += "|do_exit"; - blfn_ret += "|sys_exit"; - blfn_ret += "|sys_exit_group"; - blfn += ")$"; blfn_ret += ")$"; blfile += ")$"; + if (sess.verbose > 2) + { + clog << "blacklist regexps:" << endl; + clog << "blfn: " << blfn << endl; + clog << "blfn_ret: " << blfn_ret << endl; + clog << "blfile: " << blfile << endl; + } + int rc = regcomp (& blacklist_func, blfn.c_str(), REG_NOSUB|REG_EXTENDED); if (rc) throw semantic_error ("blacklist_func regcomp failed"); rc = regcomp (& blacklist_func_ret, blfn_ret.c_str(), REG_NOSUB|REG_EXTENDED); @@ -2804,7 +2807,8 @@ query_func_info (Dwarf_Addr entrypc, } else { - if (q->sess.prologue_searching) + if (q->sess.prologue_searching + && !q->has_statement_str && !q->has_statement_num) // PR 2608 { if (fi.prologue_end == 0) throw semantic_error("could not find prologue-end " @@ -2913,7 +2917,6 @@ static int query_dwarf_func (Dwarf_Die * func, void * arg) { dwarf_query * q = static_cast(arg); - assert (!q->has_statement_num); try { @@ -2941,11 +2944,12 @@ query_dwarf_func (Dwarf_Die * func, void * arg) { record_this_function = true; } - else if (q->has_function_num) + else if (q->has_function_num || q->has_statement_num) { - Dwarf_Addr query_addr = q->function_num_val; - query_addr = q->dw.module_address_to_global(query_addr); - + Dwarf_Addr query_addr = + q->dw.module_address_to_global(q->has_function_num ? q->function_num_val : + q->has_statement_num ? q->statement_num_val : + (assert(0) , 0)); Dwarf_Die d; q->dw.function_die (&d); @@ -2958,22 +2962,33 @@ query_dwarf_func (Dwarf_Die * func, void * arg) if (q->sess.verbose>2) clog << "selected function " << q->dw.function_name << "\n"; - Dwarf_Addr entrypc; - if (q->dw.function_entrypc (&entrypc)) - { - func_info func; - q->dw.function_die (&func.die); - func.name = q->dw.function_name; - q->dw.function_file (&func.decl_file); - q->dw.function_line (&func.decl_line); - q->filtered_functions[entrypc] = func; - + func_info func; + q->dw.function_die (&func.die); + func.name = q->dw.function_name; + q->dw.function_file (&func.decl_file); + q->dw.function_line (&func.decl_line); + + if (q->has_function_num || q->has_function_str || q->has_statement_str) + { + Dwarf_Addr entrypc; + if (q->dw.function_entrypc (&entrypc)) + q->filtered_functions[entrypc] = func; + else + throw semantic_error("no entrypc found for function '" + + q->dw.function_name + "'"); + } + else if (q->has_statement_num) + { + Dwarf_Addr probepc = q->statement_num_val; + q->filtered_functions[probepc] = func; if (q->dw.function_name_final_match (q->function)) return DWARF_CB_ABORT; - } - else - throw semantic_error("no entrypc found for function '" - + q->dw.function_name + "'"); + } + else + assert(0); + + if (q->dw.function_name_final_match (q->function)) + return DWARF_CB_ABORT; } } return DWARF_CB_OK; @@ -2998,7 +3013,7 @@ query_cu (Dwarf_Die * cudie, void * arg) clog << "focused on CU '" << q->dw.cu_name << "', in module '" << q->dw.module_name << "'\n"; - if (q->has_statement_str + if (q->has_statement_str || q->has_statement_num || q->has_function_str || q->has_function_num) { q->filtered_srcfiles.clear(); @@ -3029,7 +3044,8 @@ query_cu (Dwarf_Die * cudie, void * arg) // all in a single pass. q->dw.iterate_over_functions (query_dwarf_func, q); - if (q->sess.prologue_searching) + if (q->sess.prologue_searching + && !q->has_statement_str && !q->has_statement_num) // PR 2608 if (! q->filtered_functions.empty()) q->dw.resolve_prologue_endings (q->filtered_functions); @@ -3045,32 +3061,35 @@ query_cu (Dwarf_Die * cudie, void * arg) } else { - // Otherwise, simply probe all resolved functions (if - // we're scanning functions) - if (q->has_statement_str || q->has_function_str || q->has_function_num) - for (map::iterator i = q->filtered_functions.begin(); - i != q->filtered_functions.end(); ++i) - query_func_info (i->first, i->second, q); - - // Or all inline instances (if we're scanning inlines) - if (q->has_statement_str - || ((q->has_function_str || q->has_function_num) && !q->has_call)) + // Otherwise, simply probe all resolved functions. + for (map::iterator i = q->filtered_functions.begin(); + i != q->filtered_functions.end(); ++i) + query_func_info (i->first, i->second, q); + + // And all inline instances (if we're not excluding inlines with ".call") + if (! q->has_call) for (map::iterator i = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) query_inline_instance_info (i->first, i->second, q); - } } else { + // Before PR 5787, we used to have this: +#if 0 // Otherwise we have a statement number, and we can just // query it directly within this module. - assert (q->has_statement_num); Dwarf_Addr query_addr = q->statement_num_val; query_addr = q->dw.module_address_to_global(query_addr); query_statement ("", "", -1, NULL, query_addr, q); +#endif + // But now, we traverse CUs/functions even for + // statement_num's, for blacklist sensitivity and $var + // resolution purposes. + + assert (0); // NOTREACHED } return DWARF_CB_OK; } diff --git a/testsuite/systemtap.base/stmtvars.exp b/testsuite/systemtap.base/stmtvars.exp new file mode 100644 index 00000000..6e950ea0 --- /dev/null +++ b/testsuite/systemtap.base/stmtvars.exp @@ -0,0 +1,31 @@ +set test "stmtvars" +# PR 5787 + +set pc 0 +set vars "" +spawn stap -e "probe kernel.function(\"sys_open\") {\$foo}" -p4 -vv -u +expect { + -re {probe sys_open.*pc=(0x.*)\r\n} { set pc $expect_out(1,string); exp_continue } + -re {alternatives: ([^\r\n]*) identifier [^\r\n]*\r\n} { set vars $expect_out(1,string) + exp_continue } + timeout { fail "$test (timeout)" } + eof + } +wait +verbose -log "pc=$pc vars=$vars" +if {$pc != 0 && $vars != ""} { pass "$test - .function" } { fail "$test - .function" } + +set pc2 0 +set vars2 "" +spawn stap -e "probe kernel.statement($pc) {\$foo}" -p4 -vv -u +expect { + -re {probe sys_open.*pc=(0x.*)\r\n} { set pc2 $expect_out(1,string); exp_continue } + -re {alternatives: ([^\r\n]*) identifier [^\r\n]*\r\n} { set vars2 $expect_out(1,string) + exp_continue } + timeout { fail "$test (timeout)" } + eof + } +wait + +verbose -log "pc2=$pc2 vars2=$vars2" +if {$pc == $pc2 && $vars == $vars2} { pass $test } { fail $test } -- cgit From 3b122c7377875663429097b2138c38f3f13850b2 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 22 Feb 2008 22:37:48 -0500 Subject: 2008-02-22 Frank Ch. Eigler * test.tcl: Support noexec /tmp by creating test directory under build tree instead of /tmp. --- testsuite/systemtap.syscall/ChangeLog | 6 ++++++ testsuite/systemtap.syscall/test.tcl | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/testsuite/systemtap.syscall/ChangeLog b/testsuite/systemtap.syscall/ChangeLog index 1d234d3a..0a3d51ae 100644 --- a/testsuite/systemtap.syscall/ChangeLog +++ b/testsuite/systemtap.syscall/ChangeLog @@ -1,4 +1,10 @@ +2008-02-22 Frank Ch. Eigler + + * test.tcl: Support noexec /tmp by creating test directory + under build tree instead of /tmp. + 2007-10-12 David Wilder + * timer.c: init tid to 0 to workaround bug on s390x. 2007-10-11 David Wilder diff --git a/testsuite/systemtap.syscall/test.tcl b/testsuite/systemtap.syscall/test.tcl index a3ac7f49..66a943d6 100755 --- a/testsuite/systemtap.syscall/test.tcl +++ b/testsuite/systemtap.syscall/test.tcl @@ -32,7 +32,7 @@ proc run_one_test {filename flags} { set testname [file tail [string range $filename 0 end-2]] set result "UNSUPP" - if {[catch {exec mktemp -td staptestXXXXX} dir]} { + if {[catch {exec mktemp -d [pwd]/staptestXXXXX} dir]} { puts stderr "Failed to create temporary directory: $dir" cleanup } -- cgit From 53de687e0ca376db7ff55219833542982e477900 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 23 Feb 2008 15:36:53 -0500 Subject: PR5770: false systemtap/eof/timeout messages in testsuite.log 2008-02-23 Frank Ch. Eigler * */*.exp: Change all "send \003" to "exec kill -INT -" in order to more reliably kill an inferior stap/stapio/staprun process group. --- testsuite/ChangeLog | 5 +++++ testsuite/lib/stap_run.exp | 5 +++-- testsuite/systemtap.base/onoffprobe.exp | 2 +- testsuite/systemtap.base/overload.exp | 5 +++-- testsuite/systemtap.context/args.tcl | 2 +- testsuite/systemtap.context/backtrace.tcl | 2 +- testsuite/systemtap.context/context.exp | 2 +- testsuite/systemtap.maps/ix_clear.exp | 2 +- testsuite/systemtap.maps/ix_clear2.exp | 2 +- testsuite/systemtap.maps/ix_clear3.exp | 2 +- testsuite/systemtap.maps/pmap_agg_overflow.exp | 2 +- testsuite/systemtap.printf/sharedbuf.exp | 2 +- testsuite/systemtap.samples/crash.exp | 2 +- testsuite/systemtap.stress/whitelist.exp | 4 ++-- 14 files changed, 23 insertions(+), 16 deletions(-) diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 2a384fdc..c3ee8d1e 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-02-23 Frank Ch. Eigler + + * */*.exp: Change all "send \003" to "exec kill -INT -" in order + to more reliably kill an inferior stap/stapio/staprun process group. + 2008-02-22 Frank Ch. Eigler * semko/fortyfive.stp: Add ".call" to exclude false (?) positives diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index 5bd1549c..c2b4e74d 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -50,7 +50,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } } } - send "\003" + exec kill -INT -[exp_pid] # check the output to see if it is sane set output "^systemtap ending probe\r\n$OUTPUT_CHECK_STRING" @@ -78,7 +78,8 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } } } -re "semantic error:" { fail "$TEST_NAME compilation" } - timeout { fail "$TEST_NAME startup (timeout)"; send "\003" } + timeout { fail "$TEST_NAME startup (timeout)" + exec kill -INT [exp_pid] } eof { fail "$TEST_NAME startup (eof)" } } catch close diff --git a/testsuite/systemtap.base/onoffprobe.exp b/testsuite/systemtap.base/onoffprobe.exp index b86de4ea..24012cac 100644 --- a/testsuite/systemtap.base/onoffprobe.exp +++ b/testsuite/systemtap.base/onoffprobe.exp @@ -32,7 +32,7 @@ expect { timeout { fail "$test (timeout)" } eof { } } -send "\003" +exec kill -INT -[exp_pid] #FIXME does not handle case of hanging pfaults.stp correctly wait exec rm -f $test.ko diff --git a/testsuite/systemtap.base/overload.exp b/testsuite/systemtap.base/overload.exp index db7f49ef..cbcbe817 100644 --- a/testsuite/systemtap.base/overload.exp +++ b/testsuite/systemtap.base/overload.exp @@ -37,7 +37,7 @@ proc stap_run_overload { TEST_NAME EXPECT_OVERLOAD args } { } } -re "^systemtap starting probe\r\n" { - send "\003" + exec kill -INT -[exp_pid] expect { -timeout 10 @@ -58,7 +58,8 @@ proc stap_run_overload { TEST_NAME EXPECT_OVERLOAD args } { } } -re "semantic error:" { fail "$TEST_NAME compilation" } - timeout { fail "$TEST_NAME startup (timeout)"; send "\003" } + timeout { fail "$TEST_NAME startup (timeout)"; + exec kill -INT -[exp_pid] } eof { fail "$TEST_NAME startup (eof)" } } catch close diff --git a/testsuite/systemtap.context/args.tcl b/testsuite/systemtap.context/args.tcl index 37a43823..7cb79cdf 100644 --- a/testsuite/systemtap.context/args.tcl +++ b/testsuite/systemtap.context/args.tcl @@ -53,6 +53,6 @@ expect { } eof {fail "function arguments: unexpected timeout"} } -send "\003" +exec kill -INT -[exp_pid] close wait diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl index 703f0ec2..f359cd41 100644 --- a/testsuite/systemtap.context/backtrace.tcl +++ b/testsuite/systemtap.context/backtrace.tcl @@ -117,7 +117,7 @@ expect { } eof {fail "backtrace of yyy_func3, yyy_func4.return and timer.profile. unexpected EOF" } } -send "\003" +exec kill -INT -[exp_pid] if {$m1 == 4} { pass "backtrace of yyy_func3" } else { diff --git a/testsuite/systemtap.context/context.exp b/testsuite/systemtap.context/context.exp index 11c0f2fc..71201a58 100644 --- a/testsuite/systemtap.context/context.exp +++ b/testsuite/systemtap.context/context.exp @@ -11,7 +11,7 @@ set build_dir "" proc cleanup {} { global build_dir - catch {send "\003"} + catch { exec kill -INT -[exp_pid] } foreach n {1 2} { as_root [list /bin/rm -f /lib/modules/$::uname/kernel/systemtap_test_module$n.ko] as_root [list /sbin/rmmod systemtap_test_module$n] diff --git a/testsuite/systemtap.maps/ix_clear.exp b/testsuite/systemtap.maps/ix_clear.exp index 0c6ca6c3..07417898 100644 --- a/testsuite/systemtap.maps/ix_clear.exp +++ b/testsuite/systemtap.maps/ix_clear.exp @@ -14,7 +14,7 @@ expect { pass "$test passed" } timeout { - send "\003" + exec kill -INT -[exp_pid] fail "$test timed out" } eof { diff --git a/testsuite/systemtap.maps/ix_clear2.exp b/testsuite/systemtap.maps/ix_clear2.exp index c5e72c36..a1b68628 100644 --- a/testsuite/systemtap.maps/ix_clear2.exp +++ b/testsuite/systemtap.maps/ix_clear2.exp @@ -15,7 +15,7 @@ expect { pass "$test passed" } timeout { - send "\003" + exec kill -INT -[exp_pid] fail "$test timed out" } eof { diff --git a/testsuite/systemtap.maps/ix_clear3.exp b/testsuite/systemtap.maps/ix_clear3.exp index 7674fdbc..a2935470 100644 --- a/testsuite/systemtap.maps/ix_clear3.exp +++ b/testsuite/systemtap.maps/ix_clear3.exp @@ -13,7 +13,7 @@ expect { pass "$test passed" } timeout { - send "\003" + exec kill -INT -[exp_pid] fail "$test timed out" } eof { diff --git a/testsuite/systemtap.maps/pmap_agg_overflow.exp b/testsuite/systemtap.maps/pmap_agg_overflow.exp index 1b0a7234..99665057 100644 --- a/testsuite/systemtap.maps/pmap_agg_overflow.exp +++ b/testsuite/systemtap.maps/pmap_agg_overflow.exp @@ -19,7 +19,7 @@ expect { set unsupported 1 } timeout { - send "\003" + exec kill -INT -[exp_pid] fail "$test timed out" } eof {} diff --git a/testsuite/systemtap.printf/sharedbuf.exp b/testsuite/systemtap.printf/sharedbuf.exp index 6a182716..b1fd4c72 100644 --- a/testsuite/systemtap.printf/sharedbuf.exp +++ b/testsuite/systemtap.printf/sharedbuf.exp @@ -52,7 +52,7 @@ expect { } eof {fail "shared buffer hosting. unexpected EOF" } } -send "\003" +exec kill -INT -[exp_pid] if {$c1 == 2 && $c2 == 2} { pass "buffer sharing" } else { diff --git a/testsuite/systemtap.samples/crash.exp b/testsuite/systemtap.samples/crash.exp index 629cff54..9c3e5e05 100644 --- a/testsuite/systemtap.samples/crash.exp +++ b/testsuite/systemtap.samples/crash.exp @@ -19,7 +19,7 @@ expect { timeout { fail "$test - testlog.stp timeout" } timeout { fail "$test - testlog.stp eof" } } -catch { send "\003"; close ; wait } +catch { exec kill -INT -[exp_pid]; close ; wait } # The crash(8) script creates testlog/global or testlog/cpu as_root { chmod -R a+rX testlog } diff --git a/testsuite/systemtap.stress/whitelist.exp b/testsuite/systemtap.stress/whitelist.exp index 00a8208a..4a31c124 100644 --- a/testsuite/systemtap.stress/whitelist.exp +++ b/testsuite/systemtap.stress/whitelist.exp @@ -310,14 +310,14 @@ proc whitelist_run { TEST_NAME {LOAD_GEN_FUNCTION ""} args } { -re {Pass\ 5:\ starting\ run.\r\n} { set error_msg "stap runtime" runbenchs - send -i $stap_id "\003" + exec kill -INT -[exp_pid -i $stap_id] exp_continue } -re {Pass\ 5:\ run\ completed} { set failed 0 } -re {parse\ error|semantic\ error} { set detail "$expect_out(0,string)" } - timeout { set detail "stap timeout"; send "\003" } + timeout { set detail "stap timeout"; exec kill -INT -[exp_pid -i $stap_id] } eof { set failed 0 } } catch {close -i $stap_id} -- cgit From aaf2af3e3b0c159a64609c82811662d7253c3a96 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Mar 2008 11:32:58 -0400 Subject: rebased unwind_branch on top of current master --- .gitignore | 6 + ChangeLog | 16 - Makefile.am | 13 +- Makefile.in | 49 +- doc/ChangeLog | 4 - doc/langref.tex | 24 +- runtime/.gitignore | 1 + runtime/Makefile | 15 - runtime/bench2/Makefile | 7 - runtime/debug.h | 60 +- runtime/lket/b2a/.cvsignore | 1 - runtime/lket/b2a/Makefile.am | 18 - runtime/lket/b2a/Makefile.in | 449 ------------ runtime/lket/b2a/lket_b2a.c | 1030 ---------------------------- runtime/lket/b2a/lket_b2a.h | 101 --- runtime/map.c | 1 - runtime/probes.c | 12 +- runtime/probes/bench/Makefile | 10 - runtime/runtime.h | 1 - runtime/stack-x86_64.c | 37 +- runtime/stack.c | 3 +- runtime/staprun/mainloop.c | 159 +++-- runtime/staprun/staprun.c | 3 - runtime/staprun/staprun.h | 3 +- runtime/staprun/staprun_funcs.c | 92 --- runtime/staprun/unwind_data.c | 97 +++ runtime/sym.c | 6 +- runtime/sym.h | 24 +- runtime/tests/Makefile | 3 - runtime/tests/agg/Makefile | 5 - runtime/tests/maps/Makefile | 5 - runtime/tests/math/Makefile | 5 - runtime/tests/pmaps/Makefile | 5 - runtime/tests/string/Makefile | 5 - runtime/transport/control.c | 225 +----- runtime/transport/procfs.c | 2 +- runtime/transport/symbols.c | 606 ++++++++-------- runtime/transport/transport.c | 148 ++-- runtime/transport/transport.h | 20 +- runtime/transport/transport_msgs.h | 63 +- runtime/unwind.c | 895 ++++++++++++++++++++++++ runtime/uprobes/Makefile | 16 - safety/README | 10 - safety/data/opcodes-i686 | 107 --- safety/data/opcodes-ia64 | 89 --- safety/data/opcodes-x86_64 | 104 --- safety/data/references | 94 --- safety/safety.py | 245 ------- stap.1.in | 17 +- stapfuncs.5.in | 54 -- tapset/ChangeLog | 8 - tapset/conversions.stp | 130 +--- testsuite/ChangeLog | 18 - testsuite/buildok/conversions-embedded.stp | 13 - testsuite/buildok/conversions.stp | 13 - testsuite/lib/stap_run.exp | 14 +- testsuite/lib/systemtap.exp | 5 +- testsuite/systemtap.stress/conversions.stp | 12 - translate.cxx | 95 +-- vim/filetype.vim | 10 - vim/ftplugin/stap.vim | 25 - vim/indent/stap.vim | 35 - vim/syntax/stap.vim | 97 --- 63 files changed, 1693 insertions(+), 3747 deletions(-) create mode 100644 runtime/.gitignore delete mode 100644 runtime/Makefile delete mode 100644 runtime/bench2/Makefile delete mode 100644 runtime/lket/b2a/.cvsignore delete mode 100644 runtime/lket/b2a/Makefile.am delete mode 100644 runtime/lket/b2a/Makefile.in delete mode 100644 runtime/lket/b2a/lket_b2a.c delete mode 100644 runtime/lket/b2a/lket_b2a.h delete mode 100644 runtime/probes/bench/Makefile create mode 100644 runtime/staprun/unwind_data.c delete mode 100644 runtime/tests/Makefile delete mode 100644 runtime/tests/agg/Makefile delete mode 100644 runtime/tests/maps/Makefile delete mode 100644 runtime/tests/math/Makefile delete mode 100644 runtime/tests/pmaps/Makefile delete mode 100644 runtime/tests/string/Makefile create mode 100644 runtime/unwind.c delete mode 100644 runtime/uprobes/Makefile delete mode 100644 safety/README delete mode 100644 safety/data/opcodes-i686 delete mode 100644 safety/data/opcodes-ia64 delete mode 100644 safety/data/opcodes-x86_64 delete mode 100644 safety/data/references delete mode 100755 safety/safety.py delete mode 100644 vim/filetype.vim delete mode 100644 vim/ftplugin/stap.vim delete mode 100644 vim/indent/stap.vim delete mode 100644 vim/syntax/stap.vim diff --git a/.gitignore b/.gitignore index 69bd5e97..1c02452b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,9 @@ systemtap.spec testresults stapio stap_merge +CVS +.checkstyle +.cproject +.metadata +.project +.settings diff --git a/ChangeLog b/ChangeLog index 046804c7..c7bb82c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,19 +1,3 @@ -2008-03-25 Frank Ch. Eigler - - * stap.1.in: Clarify utility of epilogue type probe aliases. - -2008-03-21 Eugene Teo - - PR 5528 - * tapset/conversions.stp (user_string_n, user_string_n2, - user_string_n_warn, user_string_n_quoted, user_short, user_short_warn, - user_int, user_int_warn, user_long, user_long_warn, user_char, - user_char_warn): New user_* functions. - * stapfuncs.5.in: Documented the new functions. - * testsuite/systemtap.stress/conversions.stp: Test new functions. - * testsuite/buildok/conversions.stp: Test new functions. - * testsuite/buildok/conversions-embedded.stp: Test new functions. - 2008-03-20 Frank Ch. Eigler PR 5975. diff --git a/Makefile.am b/Makefile.am index 1fc4dbec..a53fdba0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,19 +53,19 @@ endif staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c runtime/staprun/symbols.c + runtime/staprun/cap.c staprun_CPPFLAGS = $(AM_CPPFLAGS) -staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread +staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED +staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ - runtime/staprun/ctl.c \ + runtime/staprun/ctl.c runtime/staprun/unwind_data.c \ runtime/staprun/relay.c runtime/staprun/relay_old.c stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -stapio_LDADD = @PROCFLAGS@ -lpthread +stapio_LDADD = @PROCFLAGS@ -ldw -lpthread install-exec-hook: if [ `id -u` -eq 0 ]; then chmod 04111 "$(DESTDIR)$(bindir)/staprun"; fi @@ -127,8 +127,9 @@ dist-hook: dist-add-samples find $(distdir) -name 'stap' -o -name '*.log' -o -name '*.sum' -o -name 'site.exp' | xargs rm -rf install-data-local: -# mkdir -p $(DESTDIR)$(pkgdatadir)/runtime/transport $(DESTDIR)$(pkgdatadir)/tapset (cd $(srcdir)/runtime; for f in *.[ch]; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/$$f; done) + (cd $(srcdir)/runtime/unwind; find . \( -name '*.[ch]' \) -print \ + | while read f; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/unwind/$$f; done) (cd $(srcdir)/runtime/transport; for f in *.[ch]; \ do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/transport/$$f; done) (cd $(srcdir)/runtime/uprobes; for f in Makefile *.[ch]; \ diff --git a/Makefile.in b/Makefile.in index e82d66a3..9fc103d3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,15 +102,15 @@ stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \ $(LDFLAGS) -o $@ am_stapio_OBJECTS = stapio-stapio.$(OBJEXT) stapio-mainloop.$(OBJEXT) \ stapio-common.$(OBJEXT) stapio-ctl.$(OBJEXT) \ - stapio-relay.$(OBJEXT) stapio-relay_old.$(OBJEXT) + stapio-unwind_data.$(OBJEXT) stapio-relay.$(OBJEXT) \ + stapio-relay_old.$(OBJEXT) stapio_OBJECTS = $(am_stapio_OBJECTS) stapio_DEPENDENCIES = stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_staprun_OBJECTS = staprun-staprun.$(OBJEXT) \ staprun-staprun_funcs.$(OBJEXT) staprun-ctl.$(OBJEXT) \ - staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT) \ - staprun-symbols.$(OBJEXT) + staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT) staprun_OBJECTS = $(am_staprun_OBJECTS) staprun_DEPENDENCIES = staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -286,18 +286,18 @@ CLEANFILES = $(am__append_3) $(pkglibexec_PROGRAMS) @BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c runtime/staprun/symbols.c + runtime/staprun/cap.c staprun_CPPFLAGS = $(AM_CPPFLAGS) -staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread +staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED +staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ - runtime/staprun/ctl.c \ + runtime/staprun/ctl.c runtime/staprun/unwind_data.c \ runtime/staprun/relay.c runtime/staprun/relay_old.c stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -stapio_LDADD = @PROCFLAGS@ -lpthread +stapio_LDADD = @PROCFLAGS@ -ldw -lpthread loc2c_test_SOURCES = loc2c-test.c loc2c.c loc2c_test_CPPFLAGS = $(stap_CPPFLAGS) loc2c_test_LDFLAGS = $(stap_LDFLAGS) @@ -505,12 +505,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay_old.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-stapio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-unwind_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-cap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-ctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun_funcs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-symbols.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -638,6 +638,20 @@ stapio-ctl.obj: runtime/staprun/ctl.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-ctl.obj `if test -f 'runtime/staprun/ctl.c'; then $(CYGPATH_W) 'runtime/staprun/ctl.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/ctl.c'; fi` +stapio-unwind_data.o: runtime/staprun/unwind_data.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-unwind_data.o -MD -MP -MF $(DEPDIR)/stapio-unwind_data.Tpo -c -o stapio-unwind_data.o `test -f 'runtime/staprun/unwind_data.c' || echo '$(srcdir)/'`runtime/staprun/unwind_data.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-unwind_data.Tpo $(DEPDIR)/stapio-unwind_data.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/unwind_data.c' object='stapio-unwind_data.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-unwind_data.o `test -f 'runtime/staprun/unwind_data.c' || echo '$(srcdir)/'`runtime/staprun/unwind_data.c + +stapio-unwind_data.obj: runtime/staprun/unwind_data.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-unwind_data.obj -MD -MP -MF $(DEPDIR)/stapio-unwind_data.Tpo -c -o stapio-unwind_data.obj `if test -f 'runtime/staprun/unwind_data.c'; then $(CYGPATH_W) 'runtime/staprun/unwind_data.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/unwind_data.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-unwind_data.Tpo $(DEPDIR)/stapio-unwind_data.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/unwind_data.c' object='stapio-unwind_data.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-unwind_data.obj `if test -f 'runtime/staprun/unwind_data.c'; then $(CYGPATH_W) 'runtime/staprun/unwind_data.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/unwind_data.c'; fi` + stapio-relay.o: runtime/staprun/relay.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay.o -MD -MP -MF $(DEPDIR)/stapio-relay.Tpo -c -o stapio-relay.o `test -f 'runtime/staprun/relay.c' || echo '$(srcdir)/'`runtime/staprun/relay.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-relay.Tpo $(DEPDIR)/stapio-relay.Po @@ -736,20 +750,6 @@ staprun-cap.obj: runtime/staprun/cap.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi` -staprun-symbols.o: runtime/staprun/symbols.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-symbols.o -MD -MP -MF $(DEPDIR)/staprun-symbols.Tpo -c -o staprun-symbols.o `test -f 'runtime/staprun/symbols.c' || echo '$(srcdir)/'`runtime/staprun/symbols.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-symbols.Tpo $(DEPDIR)/staprun-symbols.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/symbols.c' object='staprun-symbols.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-symbols.o `test -f 'runtime/staprun/symbols.c' || echo '$(srcdir)/'`runtime/staprun/symbols.c - -staprun-symbols.obj: runtime/staprun/symbols.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-symbols.obj -MD -MP -MF $(DEPDIR)/staprun-symbols.Tpo -c -o staprun-symbols.obj `if test -f 'runtime/staprun/symbols.c'; then $(CYGPATH_W) 'runtime/staprun/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/symbols.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-symbols.Tpo $(DEPDIR)/staprun-symbols.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/symbols.c' object='staprun-symbols.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-symbols.obj `if test -f 'runtime/staprun/symbols.c'; then $(CYGPATH_W) 'runtime/staprun/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/symbols.c'; fi` - .cxx.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @@ -1498,8 +1498,9 @@ dist-hook: dist-add-samples find $(distdir) -name 'stap' -o -name '*.log' -o -name '*.sum' -o -name 'site.exp' | xargs rm -rf install-data-local: -# mkdir -p $(DESTDIR)$(pkgdatadir)/runtime/transport $(DESTDIR)$(pkgdatadir)/tapset (cd $(srcdir)/runtime; for f in *.[ch]; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/$$f; done) + (cd $(srcdir)/runtime/unwind; find . \( -name '*.[ch]' \) -print \ + | while read f; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/unwind/$$f; done) (cd $(srcdir)/runtime/transport; for f in *.[ch]; \ do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/transport/$$f; done) (cd $(srcdir)/runtime/uprobes; for f in Makefile *.[ch]; \ diff --git a/doc/ChangeLog b/doc/ChangeLog index e652078d..902e1d1e 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,7 +1,3 @@ -2008-03-25 Frank Ch. Eigler - - * langref.tex: Clarify utility of epilogue-type probe aliases. - 2008-03-04 David Smith * tutorial.tex: Made minor changes to remove warnings. diff --git a/doc/langref.tex b/doc/langref.tex index 973769d4..5b91d01d 100644 --- a/doc/langref.tex +++ b/doc/langref.tex @@ -230,7 +230,7 @@ This prints: \end{verbatim} \end{vindent} Any larger number input to the function may exceed the MAXACTION or MAXNESTING -limits, which will be caught at run time and result in an error. For more +limits, which will be caught by the parser and result in an error. For more about limits see Section~\ref{sub:SystemTap-safety}. \newpage{} \subsection{The stap command} @@ -436,10 +436,8 @@ probe syscall.read = kernel.function("sys_read") { \index{epilogue-style aliases} \index{+=} The statement block that follows an alias definition is implicitly added -as an epilogue to any probe that refers to the alias. It is not useful -to define new variable there (since no subsequent code will see it), but -rather the code can take action based upon variables left set by the -prologue or by the user code. The following is an example: +as an epilogue to any probe that refers to the alias. The following is an +example: \begin{vindent} \begin{verbatim} @@ -447,15 +445,15 @@ prologue or by the user code. The following is an example: # epilogue. # probe syscall.read += kernel.function("sys_read") { - if (traceme) println ("tracing me") + fildes = $fd } \end{verbatim} \end{vindent} \subsubsection{Probe alias usage} -A probe alias is used the same way as any built-in probe type, by -naming it: +Another probe definition may use a previously defined alias. The following +is an example. \begin{vindent} \begin{verbatim} @@ -1029,6 +1027,12 @@ type conversions between strings and numbers. Inconsistent type-related use of identifiers signals an error. +\subsubsection{Numbers} +\index{numbers} +Numbers are 64-bit signed integers. The parser will also accept (and wrap +around) values above positive $2^{63}$. + + \subsubsection{Literals} \index{literals} Literals are either strings or integers. Literals can be expressed as decimal, @@ -1037,10 +1041,10 @@ octal, or hexadecimal, using C notation. Type suffixes (e.g., \emph{L} or \subsubsection{Integers\label{sub:Integers}} -\index{integers} \index{numbers} +\index{integers} Integers are decimal, hexadecimal, or octal, and use the same notation as in C. Integers are 64-bit signed quantities, although the parser also accepts -(and wraps around) values above positive $2^{63}$ but below $2^{64}$. +(and wraps around) values above positive $2^{63}$. \subsubsection{Strings\label{sub:Strings}} diff --git a/runtime/.gitignore b/runtime/.gitignore new file mode 100644 index 00000000..ceddd64c --- /dev/null +++ b/runtime/.gitignore @@ -0,0 +1 @@ +!staprun diff --git a/runtime/Makefile b/runtime/Makefile deleted file mode 100644 index 22d25ff9..00000000 --- a/runtime/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for SystemTap runtime and example probes -# - -all: - make -w -C stpd - cd probes; ./build - -relayfs: - make -w -C relayfs - -clean: - make -w -C relayfs clean - make -w -C stpd clean - cd probes; ./build clean diff --git a/runtime/bench2/Makefile b/runtime/bench2/Makefile deleted file mode 100644 index ffb2991a..00000000 --- a/runtime/bench2/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: itest - -itest: itest.c - gcc -D_GNU_SOURCE -Wall -Wextra -Wstrict-prototypes -Werror -O3 -o itest itest.c -lpthread - -clean: - /bin/rm -f itest diff --git a/runtime/debug.h b/runtime/debug.h index 8f877ede..9b2fe5c5 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -14,6 +14,8 @@ * _dbug() writes to systemtap stderr. * errk() writes to the system log. */ +int _stp_transport_state = 0; + #define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) #define errk(args...) do { \ @@ -21,46 +23,42 @@ printk(args); \ } while (0) -#ifdef DEBUG_TRANSPORT -#undef DEBUG_TRANSPORT -#define DEBUG_TRANSPORT 1 -#else -#define DEBUG_TRANSPORT 0 -#endif +/* + * To use these, enable them from the command line when compiling. + * For example, "stap -DDEBUG_UNWIND=3" + * will activate dbug_unwind() and print messages with level <= 3. + */ -#ifdef DEBUG_UNWIND -#undef DEBUG_UNWIND -#define DEBUG_UNWIND 2 -#else -#define DEBUG_UNWIND 0 -#endif +/* Note: DEBUG_MEM is implemented in alloc.c */ -#ifdef DEBUG_SYMBOLS -#undef DEBUG_SYMBOLS -#define DEBUG_SYMBOLS 4 +#ifdef DEBUG_TRANS /* transport */ +/* Note: transport is debugged using printk() */ +#define dbug_trans(level, args...) do { \ + if ((level) <= DEBUG_TRANS) { \ + printk("%s:%d ",__FUNCTION__, __LINE__); \ + printk(args); \ + } \ + } while (0) #else -#define DEBUG_SYMBOLS 0 +#define dbug_trans(level, args...) ; #endif -#define DEBUG_TYPE (DEBUG_TRANSPORT|DEBUG_UNWIND|DEBUG_SYMBOLS) - -#if DEBUG_TYPE > 0 - -#define dbug(type, args...) do { \ - if ((type) & DEBUG_TYPE) \ +#ifdef DEBUG_UNWIND /* stack unwinder */ +#define dbug_unwind(level, args...) do { \ + if ((level) <= DEBUG_UNWIND) \ _stp_dbug(__FUNCTION__, __LINE__, args); \ } while (0) +#else +#define dbug_unwind(level, args...) ; +#endif -#define kbug(type, args...) do { \ - if ((type) & DEBUG_TYPE) { \ - printk("%s:%d ",__FUNCTION__, __LINE__); \ - printk(args); \ - } \ +#ifdef DEBUG_SYMBOLS +#define dbug_sym(level, args...) do { \ + if ((level) <= DEBUG_SYMBOLS) \ + _stp_dbug(__FUNCTION__, __LINE__, args); \ } while (0) - #else -#define dbug(type, args...) ; -#define kbug(type, args...) ; -#endif /* DEBUG_TYPE > 0 */ +#define dbug_sym(level, args...) ; +#endif #endif /* _STP_DEBUG_H_ */ diff --git a/runtime/lket/b2a/.cvsignore b/runtime/lket/b2a/.cvsignore deleted file mode 100644 index e289e6f1..00000000 --- a/runtime/lket/b2a/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile lket-b2a .deps diff --git a/runtime/lket/b2a/Makefile.am b/runtime/lket/b2a/Makefile.am deleted file mode 100644 index 01472f6a..00000000 --- a/runtime/lket/b2a/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -bin_PROGRAMS = lket-b2a -lket_b2a_SOURCES = lket_b2a.c -lket_b2a_DEPENDENCIES = lket_b2a.h -lket_b2a_LDFLAGS = `pkg-config --libs glib-2.0` -lket_b2a_CFLAGS = -O2 -D_GNU_SOURCE -Wall `pkg-config --cflags glib-2.0` - -if HAS_MYSQL -lket_b2a_CFLAGS += -DHAS_MYSQL -if HAS_MYSQL_CONFIG -lket_b2a_LDFLAGS += `mysql_config --libs` -lket_b2a_CFLAGS += `mysql_config --cflags` -else -lket_b2a_CFLAGS += -I/usr/include/mysql -g -pipe -fsigned-char -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -lket_b2a_LDFLAGS += -L/usr/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -L/usr/lib -lssl -lcrypto -endif -endif - - diff --git a/runtime/lket/b2a/Makefile.in b/runtime/lket/b2a/Makefile.in deleted file mode 100644 index e262682a..00000000 --- a/runtime/lket/b2a/Makefile.in +++ /dev/null @@ -1,449 +0,0 @@ -# Makefile.in generated by automake 1.10 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. -# This Makefile.in 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. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -bin_PROGRAMS = lket-b2a$(EXEEXT) -@HAS_MYSQL_TRUE@am__append_1 = -DHAS_MYSQL -@HAS_MYSQL_CONFIG_TRUE@@HAS_MYSQL_TRUE@am__append_2 = `mysql_config --libs` -@HAS_MYSQL_CONFIG_TRUE@@HAS_MYSQL_TRUE@am__append_3 = `mysql_config --cflags` -@HAS_MYSQL_CONFIG_FALSE@@HAS_MYSQL_TRUE@am__append_4 = -I/usr/include/mysql -g -pipe -fsigned-char -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -@HAS_MYSQL_CONFIG_FALSE@@HAS_MYSQL_TRUE@am__append_5 = -L/usr/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -L/usr/lib -lssl -lcrypto -subdir = runtime/lket/b2a -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -am__installdirs = "$(DESTDIR)$(bindir)" -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) -PROGRAMS = $(bin_PROGRAMS) -am_lket_b2a_OBJECTS = lket_b2a-lket_b2a.$(OBJEXT) -lket_b2a_OBJECTS = $(am_lket_b2a_OBJECTS) -lket_b2a_LDADD = $(LDADD) -lket_b2a_LINK = $(CCLD) $(lket_b2a_CFLAGS) $(CFLAGS) \ - $(lket_b2a_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(lket_b2a_SOURCES) -DIST_SOURCES = $(lket_b2a_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DATE = @DATE@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQL_CONFIG = @MYSQL_CONFIG@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PROCFLAGS = @PROCFLAGS@ -RANLIB = @RANLIB@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -U = @U@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build_alias = @build_alias@ -builddir = @builddir@ -cap_LIBS = @cap_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -elfutils_abs_srcdir = @elfutils_abs_srcdir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -sqlite3_LIBS = @sqlite3_LIBS@ -srcdir = @srcdir@ -stap_LIBS = @stap_LIBS@ -subdirs = @subdirs@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -lket_b2a_SOURCES = lket_b2a.c -lket_b2a_DEPENDENCIES = lket_b2a.h -lket_b2a_LDFLAGS = `pkg-config --libs glib-2.0` $(am__append_2) \ - $(am__append_5) -lket_b2a_CFLAGS = -O2 -D_GNU_SOURCE -Wall `pkg-config --cflags \ - glib-2.0` $(am__append_1) $(am__append_3) $(am__append_4) -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu runtime/lket/b2a/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu runtime/lket/b2a/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) -lket-b2a$(EXEEXT): $(lket_b2a_OBJECTS) $(lket_b2a_DEPENDENCIES) - @rm -f lket-b2a$(EXEEXT) - $(lket_b2a_LINK) $(lket_b2a_OBJECTS) $(lket_b2a_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lket_b2a-lket_b2a.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -lket_b2a-lket_b2a.o: lket_b2a.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lket_b2a_CFLAGS) $(CFLAGS) -MT lket_b2a-lket_b2a.o -MD -MP -MF $(DEPDIR)/lket_b2a-lket_b2a.Tpo -c -o lket_b2a-lket_b2a.o `test -f 'lket_b2a.c' || echo '$(srcdir)/'`lket_b2a.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/lket_b2a-lket_b2a.Tpo $(DEPDIR)/lket_b2a-lket_b2a.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lket_b2a.c' object='lket_b2a-lket_b2a.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lket_b2a_CFLAGS) $(CFLAGS) -c -o lket_b2a-lket_b2a.o `test -f 'lket_b2a.c' || echo '$(srcdir)/'`lket_b2a.c - -lket_b2a-lket_b2a.obj: lket_b2a.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lket_b2a_CFLAGS) $(CFLAGS) -MT lket_b2a-lket_b2a.obj -MD -MP -MF $(DEPDIR)/lket_b2a-lket_b2a.Tpo -c -o lket_b2a-lket_b2a.obj `if test -f 'lket_b2a.c'; then $(CYGPATH_W) 'lket_b2a.c'; else $(CYGPATH_W) '$(srcdir)/lket_b2a.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/lket_b2a-lket_b2a.Tpo $(DEPDIR)/lket_b2a-lket_b2a.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lket_b2a.c' object='lket_b2a-lket_b2a.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lket_b2a_CFLAGS) $(CFLAGS) -c -o lket_b2a-lket_b2a.obj `if test -f 'lket_b2a.c'; then $(CYGPATH_W) 'lket_b2a.c'; else $(CYGPATH_W) '$(srcdir)/lket_b2a.c'; fi` - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(PROGRAMS) -installdirs: - for dir in "$(DESTDIR)$(bindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-exec-am: install-binPROGRAMS - -install-html: install-html-am - -install-info: install-info-am - -install-man: - -install-pdf: install-pdf-am - -install-ps: install-ps-am - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-binPROGRAMS - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/runtime/lket/b2a/lket_b2a.c b/runtime/lket/b2a/lket_b2a.c deleted file mode 100644 index ab1bb299..00000000 --- a/runtime/lket/b2a/lket_b2a.c +++ /dev/null @@ -1,1030 +0,0 @@ -// Copyright (C) 2005, 2006 IBM Corp. -// Copyright (C) 2006 Red Hat Inc. -// Copyright (C) 2007 Bull S.A.S -// -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lket_b2a.h" - -/* A flag indicate whether to store the trace - data into local file/MySQL database */ -int into_file, into_db; -int name_flag=1, id_flag=0, appname_flag=1; -#ifdef HAS_MYSQL - -#define SQLSIZE 1024*1024 -int sql_count; -#define INSERT_THRESHOLD 100 -char sql[4096]; -char sqlStatement[SQLSIZE]; -char sql_col[1024]; -char sql_val[2048]; - -MYSQL mysql; -#endif - -/* A FILE handle points to a local file used to - store the trace data */ -FILE *outfp; - -#define TIMING_GETCYCLES 0x01 -#define TIMING_GETTIMEOFDAY 0x02 -#define TIMING_SCHEDCLOCK 0x03 - -typedef struct _cpufreq_info { - long timebase; - long long last_cycles; - long long last_time; -} cpufreq_info; - -#define MAX_CPUS 256 -cpufreq_info cpufreq[MAX_CPUS]; - -static long timing_method = TIMING_GETTIMEOFDAY; - -static long long start_timestamp; - -GTree *appNameTree; - -/* event table */ -event_desc *events_des[MAX_EVT_TYPES][MAX_GRPID][MAX_HOOKID]; - -#define b2a_error(fmt, args...) do { fprintf(stderr, "Error %d@%s: "fmt, __LINE__, __func__, ## args);\ - exit(-1); } while(0) - -void usage() -{ -printf("Usage:\n\ - lket-b2a Options INFILE1 [INFILE2...]\n\ - Options:\n\ - -f dump the trace data into a local file named \"lket.out\"\n\ - -n name_flag. name_flag set to 0 means not printing the event\n\ - description string and 1 means printing. Only valid with -f\n\ - option. name_flag is set to 1 by default.\n\ - -i id_flag. id_flag set to 0 means not printing event groupid and\n\ - hookid and 1 means printing. Only valid with -f option. id_flag\n\ - is set to 0 by default.\n\ - -a appname_flag. appname_flag set to 0 means not printing process\n\ - name and 1 means printing. Only valid with -f option. appname_flag\n\ - is set to 1 by default.\n\ - -m dump the trace data into MySQL\n\ - Example:\n\ - lket-b2a -f -a 1 -i 1 -n 0 stpd_cpu*\n\ - lket-b2a -m stpd_cpu*\n"); -} - -int main(int argc, char *argv[]) -{ - lket_pkt_header *hdrs = NULL; - FILE **infps = NULL; - char outfilename[MAX_STRINGLEN]={0}; - int i, j, total_infiles = 0; - long long min; - int retvalue = 0; - - char database[18]; - time_t timer; - struct tm *tm; - - time(&timer); - tm = localtime(&timer); - strftime(database, 18, "DB%Y%m%d%H%M%S", tm); - - while (1) { - int c = getopt(argc, argv, "mfi:n:a:"); - if (c < 0) // no more options - break; - switch (c) { - case 'm': - into_db = 1; - break; - case 'f': - into_file = 1; - break; - case 'n': - name_flag = atoi(optarg); - if(name_flag!=0 && name_flag!=1) { - fprintf(stderr, "you must specify 0 or 1 for -n option\n"); - usage(); - exit(-1); - } - break; - case 'i': - id_flag = atoi(optarg); - if(id_flag!=0 && id_flag!=1) { - fprintf(stderr, "you must specify 0 or 1 for -i option\n"); - usage(); - exit(-1); - } - break; - case 'a': - appname_flag = atoi(optarg); - if(appname_flag!=0 && appname_flag!=1) { - fprintf(stderr, "you must specify 0 or 1 for -a option\n"); - usage(); - exit(-1); - } - break; - - default: - printf("Error in options\n"); - usage(); - exit(-1); - break; - } - } - -#ifndef HAS_MYSQL - if(into_db) { - b2a_error("-m option is not supported since lket-b2a is not compiled with mysql support\n"); - } -#endif - if(into_file==0 && into_db==0) { -#ifdef HAS_MYSQL - fprintf(stderr, "At least one of -m/-f option should be specified\n"); -#else - fprintf(stderr, "-f option must be specified\n"); -#endif - usage(); - exit(-1); - } - - total_infiles = argc - optind; - - // open the input files and the output file - infps = (FILE **)malloc(total_infiles * sizeof(FILE *)); - if(!infps) { - b2a_error("Unable to malloc infps\n"); - } - - memset(infps, 0, total_infiles * sizeof(FILE *)); - for(i=0; i < total_infiles; i++) { - infps[i] = fopen(argv[optind++], "r"); - if(infps[i] == NULL) { - printf("Unable to open %s\n", argv[optind-1]); - retvalue = -1; - goto failed; - } - } - - if(into_file) { - if(strnlen(outfilename, MAX_STRINGLEN) == 0) - strncpy(outfilename, DEFAULT_OUTFILE_NAME, MAX_STRINGLEN); - - outfp = fopen(outfilename, "w"); - if(outfp == NULL) { - fprintf(stderr,"Unable to create %s\n", outfilename); - retvalue = -1; - goto failed; - } - } - /* create the search tree */ - appNameTree = g_tree_new_full(compareFunc, NULL, NULL, destroyTreeData); - -#ifdef HAS_MYSQL - if(into_db) { - if(!mysql_init(&mysql)) { - b2a_error("Failed to Init MySQL: Error: %s\n", - mysql_error(&mysql)); - } - - if(!mysql_real_connect(&mysql, NULL, NULL, NULL, NULL, 0, NULL, - CLIENT_MULTI_STATEMENTS)) { - b2a_error("Failed to connect to database: Error: %s\n", - mysql_error(&mysql)); - } - - snprintf(sql, 64,"create database %s", database); - - if(mysql_query(&mysql, sql)) { - b2a_error("Failed create database %s, Error: %s\n", - database, mysql_error(&mysql)); - } - - if(!mysql_real_connect(&mysql, NULL, NULL, NULL, database, 0, NULL, - CLIENT_MULTI_STATEMENTS)) { - b2a_error("Failed to connect to database %s: Error: %s\n", - database, mysql_error(&mysql)); - } - } -#endif - - // find the lket header - find_init_header(infps, total_infiles); - - // allocate packet headers array - hdrs = malloc(total_infiles * sizeof(lket_pkt_header)); - if(!hdrs) { - printf("Unable to malloc hdrs \n"); - retvalue = -1; - goto failed; - } - memset(hdrs, 0, total_infiles * sizeof(lket_pkt_header)); - - // initialize packet headers array - start_timestamp = 0; - j = 0; - for(i=0; i < total_infiles; i++) { - get_pkt_header(infps[i], &hdrs[i]); - if( (hdrs[i].microsecond < start_timestamp && hdrs[i].microsecond >0) - || (start_timestamp == 0)) { - start_timestamp = hdrs[i].microsecond; - j = i; - } - } - - // initialize the start cycles - if(timing_method == TIMING_GETCYCLES) { - for(i=0; i 0)) { - min = hdrs[i].microsecond; - j = i; - } - } - } while(min != 0); - -failed: - // close all opened files - for(i=0; i < total_infiles; i++) - if(infps[i]) - fclose(infps[i]); - if(outfp) - fclose(outfp); - - // free all allocated memory space - if(infps) - free(infps); - if(hdrs) - free(hdrs); - - for(i=1; iflag == 0 && into_db) { - snprintf(sql, 256, "drop table %d_%d",i,j); - if(mysql_query(&mysql,sql)) { - b2a_error("Failed to exec sql: %s, Error: %s\n", - sql, mysql_error(&mysql)); - } - snprintf(sql, 256, "delete from table_desc where table_name='%d_%d'",i,j); - if(mysql_query(&mysql,sql)) { - b2a_error("Failed to exec sql: %s, Error: %s\n", - sql, mysql_error(&mysql)); - } - } - /* destroy entrytime tree */ - if(events_des[_HOOKID_REGSYSEVT][i][j]->entrytime) - g_tree_destroy(events_des[_HOOKID_REGSYSEVT][i][j]->entrytime); -#endif - } - } - -#ifdef HAS_MYSQL - if(into_db) { - mysql_close(&mysql); - } -#endif - if (appNameTree) - g_tree_destroy(appNameTree); - - return retvalue; -} - -/* register newly found process name for addevent.process.snapshot - and addevent.process.execve */ -void register_appname(int i, FILE *fp, lket_pkt_header *phdr) -{ - int pid, tid, ppid; - char *appname=NULL; - int count; - int len; - int c; - int location; - len=0; - count=0; - -#ifdef HAS_MYSQL - static int flag = 0; - - if(into_db) { - if(flag==0) { - if(mysql_query(&mysql, "create table appNameMap ( pid INT, pname varchar(20))")) { - b2a_error("Failed to create appNameMap table, Error: %s\n", - mysql_error(&mysql)); - } - } - flag=1; - } -#endif - appname = (char *)malloc(512); - location = ftell(fp); - - if(HDR_HookID(phdr) == _HOOKID_PROCESS_SNAPSHOT ) { /* process_snapshot */ - fread(&tid, 1, 4, fp); /* read tid */ - fread(&pid, 1, 4, fp); /* read pid */ - fread(&ppid, 1, 4, fp); /* read ppid */ - c = fgetc_unlocked(fp); - len+=13; - while (c && len < 1024) { - appname[count++] = (char)c; - c = fgetc_unlocked(fp); - ++len; - } - appname[count]='\0'; - } else if (HDR_HookID(phdr) == _HOOKID_PROCESS_EXECVE) { /* process.execve */ - fread(&tid, 1, 4, fp); /* read tid */ - fread(&pid, 1, 4, fp); /* read pid */ - fread(&ppid, 1, 4, fp); /* read ppid */ - c = fgetc_unlocked(fp); - len+=5; - while (c && len < 1024) { - appname[count++] = (char)c; - c = fgetc_unlocked(fp); - ++len; - } - appname[count]='\0'; - } else if (HDR_HookID(phdr) == _HOOKID_PROCESS_FORK) { - fread(&tid, 1, 4, fp); /* read tid */ - fread(&pid, 1, 4, fp); /* read pid */ - fread(&ppid, 1, 4, fp); /* read ppid */ - - char *appname_ptr; - appname_ptr = (char *)(g_tree_lookup(appNameTree,(gconstpointer)((long)ppid))); - if(appname_ptr == NULL) - strncpy(appname, "N/A", 4); - else - strncpy(appname, appname_ptr, 256); - - } else { - free(appname); - return; - } - fseek(fp, location, SEEK_SET); -#ifdef HAS_MYSQL - if(into_db) { - snprintf(sql, 256,"insert into appNameMap values ( %d, \"%s\")", pid, appname); - if(mysql_query(&mysql,sql)) { - b2a_error("Failed to exec SQL: %s, Error: %s\n", - sql, mysql_error(&mysql)); - } - } -#endif - g_tree_insert(appNameTree, (gpointer)((long)pid), (gpointer)appname); -} - - -gint compareFunc(gconstpointer a, gconstpointer b, gpointer user_data) -{ - if((long)(a) > (long)(b)) return 1; - else if ((long)(a) < (long)(b)) return -1; - else return 0; -} - -void destroyTreeData(gpointer data) -{ - free(data); -} - -/* - * search the LKET init header in a set of input files, - * and the header structure is defined in tapsets/lket_trace.stp - */ -void find_init_header(FILE **infps, const int total_infiles) -{ - int i, j, k; - int32_t magic; - percpu_header pcpu; - - /* information from lket_init_header */ - int16_t inithdr_len; - int8_t ver_major; - int8_t ver_minor; - int8_t big_endian; - int8_t timing_field; - int8_t bits_width; - int32_t init_timebase; - char timing_methods_str[128]; - - if(total_infiles <= 0 ) - b2a_error("total_infiles <= 0\n"); - j = total_infiles; - for(i=0; isys_size -= sizeof(lket_pkt_header)-sizeof(phdr->total_size)-sizeof(phdr->sys_size); - phdr->total_size -= sizeof(lket_pkt_header)-sizeof(phdr->total_size)-sizeof(phdr->sys_size); - return 0; -} - -void print_pkt_header(lket_pkt_header *phdr) -{ - long long usecs; - int sec, usec; - int grpid, hookid, pid, tid, ppid; - - if(!phdr) - b2a_error("phdr is NULL\n"); - - if(timing_method == TIMING_GETCYCLES) - usecs = (phdr->microsecond - cpufreq[HDR_CpuID(phdr)].last_cycles) - / cpufreq[HDR_CpuID(phdr)].timebase + cpufreq[HDR_CpuID(phdr)].last_time; - else if(timing_method == TIMING_SCHEDCLOCK) - usecs = (phdr->microsecond - start_timestamp) / 1000; - else - usecs = phdr->microsecond - start_timestamp; - - sec = usecs/1000000; - usec = usecs%1000000; - - grpid = HDR_GroupID(phdr); - hookid = HDR_HookID(phdr); - pid = HDR_PID(phdr); - tid = HDR_TID(phdr); - ppid = HDR_PPID(phdr); - - if(into_file) { - fprintf(outfp, "\n%d.%d CPU:%d TID:%d, PID:%d, PPID:%d, ", sec, usec, - HDR_CpuID(phdr), tid, pid, ppid); - if(appname_flag==1) { - char *appname_ptr; - appname_ptr = (char *)(g_tree_lookup(appNameTree,(gconstpointer)((long)pid))); - if(appname_ptr == NULL) - fprintf(outfp, "APPNAME:N/A "); - else - fprintf(outfp, "APPNAME:%s ", appname_ptr); - } - if(name_flag==1) - fprintf(outfp, "EVT_NAME:%s ", events_des[_HOOKID_REGSYSEVT][grpid][hookid]->description); - if(id_flag==1) - fprintf(outfp, "HOOKGRP:%d HOOKID:%d ", grpid, hookid); - } - -#ifdef HAS_MYSQL - if(into_db) { - if(!(hookid%2)) { // return type event - long long *entrytime; - long long entryusecs; - entrytime = g_tree_lookup(events_des[_HOOKID_REGSYSEVT][grpid][hookid-1]->entrytime, - (gconstpointer)((long)tid)); - if(entrytime==NULL) // key not found - entryusecs = 0; - else - entryusecs = *entrytime; - snprintf(sql_col, 128, "groupid, hookid, usec, thread_id, process_id, parentprocess_id, \ - cpu_id, entry_usec,"); - snprintf(sql_val, 256, "%d, %d, %lld, %d, %d, %d, %d, %lld,", grpid, - hookid, usecs, tid, pid, ppid, HDR_CpuID(phdr), - entryusecs); - } else { - snprintf(sql_col, 128, "groupid, hookid, usec, thread_id, process_id, parentprocess_id, cpu_id,"); - snprintf(sql_val, 256, "%d, %d, %lld, %d, %d, %d, %d, ", grpid, - hookid, usecs, tid, pid, ppid, HDR_CpuID(phdr)); - } - if(hookid%2) { - char *entrytime = malloc(sizeof(long long)); - *((long long *)entrytime) = usecs; - g_tree_insert(events_des[_HOOKID_REGSYSEVT][grpid][hookid]->entrytime, - (gpointer)((long)tid), (gpointer)entrytime); - } - } -#endif - -} - -#ifdef HAS_MYSQL -char *get_sqltype(char *fmt) -{ - if(strncmp(fmt, "INT8", 4) == 0) - return "TINYINT"; - if(strncmp(fmt, "INT16", 5) == 0) - return "SMALLINT"; - if(strncmp(fmt, "INT32", 5) == 0) - return "INT"; - if(strncmp(fmt, "INT64", 5) == 0) - return "BIGINT"; - if(strncmp(fmt, "STRING", 6) == 0) - return "VARCHAR(20)"; - return ""; -} -#endif - -void register_evt_desc(FILE *infp, size_t size) -{ -#ifdef HAS_MYSQL - static int has_table = 0; -#endif - int grpid, hookid; - int len = 0; - char *evt_body; - evt_body = malloc(size); - fread(evt_body, size, 1, infp); - grpid = *(int8_t *)evt_body; - hookid = *(int8_t *)(evt_body+1); - len = strlen(evt_body+2)+2; - if(!events_des[_HOOKID_REGSYSEVT][grpid][hookid]) - events_des[_HOOKID_REGSYSEVT][grpid][hookid] = malloc(sizeof(event_desc)); - events_des[_HOOKID_REGSYSEVT][grpid][hookid]->description = malloc(len); - - strncpy(events_des[_HOOKID_REGSYSEVT][grpid][hookid]->description, evt_body+2, len); -#ifdef HAS_MYSQL - events_des[_HOOKID_REGSYSEVT][grpid][hookid]->entrytime = g_tree_new_full( - compareFunc, NULL, NULL, destroyTreeData); - if(into_db) { - if(!has_table) { - snprintf(sql, 1024, "create table table_desc ( table_name varchar(6), table_desc varchar(32))"); - if(mysql_query(&mysql, sql)) { - b2a_error("Failed exec SQL: \n %s \n, Error: %s\n", - sql, mysql_error(&mysql)); - } - has_table = 1; - } - - snprintf(sql, 1024, "insert into table_desc ( table_name, table_desc) values ( \"%d_%d\", \"%s\")", grpid, hookid, - evt_body+2); - - if(mysql_query(&mysql, sql)) { - b2a_error("Failed exec SQL:\n %s \n, Error: %s\n", - sql, mysql_error(&mysql)); - } - } -#endif - free(evt_body); -} - -void register_events(int evt_type, FILE *infp, size_t size) -{ - int cnt=0, len=0; - - char *evt_body, *evt_fmt, *evt_names, *tmp, *fmt, *name; - int8_t grpid, hookid; - - evt_body = malloc(size); - - fread(evt_body, size, 1, infp); - - grpid = *(int8_t *)evt_body; - hookid = *(int8_t *)(evt_body+1); - - if(!events_des[evt_type][grpid][hookid]) - events_des[evt_type][grpid][hookid] = malloc(sizeof(event_desc)); - if(!events_des[evt_type][grpid][hookid]) { - b2a_error("error when malloc for event_des[%d][%d][%d]\n", - evt_type, grpid, hookid); - } - -#ifdef HAS_MYSQL - if(into_db) { - if(evt_type==_HOOKID_REGSYSEVT) { /* if sys event, create a table */ - if(!(hookid%2)) {/* if this is a return type event, should record - the entry time of this event */ - snprintf(sql, 1024, "create table %d_%d ( groupid TINYINT, hookid TINYINT, usec BIGINT, thread_id INT, process_id INT, parentprocess_id INT, cpu_id TINYINT, entry_usec BIGINT,", grpid, hookid); - } else { - snprintf(sql, 1024, "create table %d_%d ( groupid TINYINT, hookid TINYINT, usec BIGINT, thread_id INT, process_id INT, parentprocess_id INT, cpu_id TINYINT,", grpid, hookid); - } - } - if(evt_type==_HOOKID_REGUSREVT) { /* if user event, alter an existing table */ - snprintf(sql, 1024, "alter table %d_%d ", grpid, hookid); - } - } - - if(size == 2) // skip if no event format is provided - goto gen_sql; -#endif - - evt_fmt = evt_body+2; - - for(tmp=evt_fmt; *tmp!=0; tmp++); - - evt_names = tmp+1; - - fmt = strsep(&evt_fmt, ":"); - name = strsep(&evt_names, ":"); - - if(fmt==NULL || name==NULL) { - b2a_error("error in event format/names string\n"); - } - - while(fmt!=NULL && name!=NULL) { -#ifdef HAS_MYSQL - if(into_db) { - if(evt_type==_HOOKID_REGSYSEVT) { - strcat(sql, "`"); - strcat(sql, name); - strcat(sql, "` "); - strcat(sql, get_sqltype(fmt)); - strcat(sql, ","); - } - if(evt_type==_HOOKID_REGUSREVT) { - strcat(sql, "add "); - strcat(sql, "`"); - strcat(sql, name); - strcat(sql, "` "); - strcat(sql, get_sqltype(fmt)); - strcat(sql, ","); - } - } -#endif - strncpy(events_des[evt_type][grpid][hookid]->evt_fmt[cnt], fmt, 7); - strncpy(events_des[evt_type][grpid][hookid]->evt_names[cnt], - name, MAX_FIELDNAME_LEN); - strncpy(events_des[evt_type][grpid][hookid]->fmt+len, get_fmtstr(fmt), 8); - len+=strlen(get_fmtstr(fmt)); - fmt = strsep(&evt_fmt, ":"); - name = strsep(&evt_names, ":"); - cnt++; - } - events_des[evt_type][grpid][hookid]->count = cnt; - *(events_des[evt_type][grpid][hookid]->fmt+len)='\0'; - -#ifdef HAS_MYSQL -gen_sql: - if(into_db) { - if(evt_type==_HOOKID_REGSYSEVT) - sql[strlen(sql)-1]=')'; - if(evt_type==_HOOKID_REGUSREVT) - sql[strlen(sql)-1]='\0'; - - if(mysql_query(&mysql, sql)) { - b2a_error("Failed exec SQL: \n %s \n, Error: %s\n", - sql, mysql_error(&mysql)); - } - } -#endif - free(evt_body); -} - -char *get_fmtstr(char *fmt) -{ - if(strncmp(fmt, "INT8", 4) == 0) - return "%1b"; - if(strncmp(fmt, "INT16", 5) == 0) - return "%2b"; - if(strncmp(fmt, "INT32", 5) == 0) - return "%4b"; - if(strncmp(fmt, "INT64", 5) == 0) - return "%8b"; - if(strncmp(fmt, "STRING", 6) == 0) - return "%0s"; - return ""; -} - -int dump_data(lket_pkt_header header, FILE *infp) -{ - int i, c, j; - int16_t stemp; - int32_t ntemp; - long long lltemp; - int readbytes = 0; - int total_bytes = 0; - int size = 0; - int evt_num = 1; - - char tmp_int[32]; - - char *fmt, *name, *buffer; - int grpid = HDR_GroupID(&header); - int hookid = HDR_HookID(&header); - - print_pkt_header(&header); - - /* if the data contains user appended extra data */ - if(header.total_size != header.sys_size) - evt_num = 3; - - /* iterate the sys and user event */ - for(j=1; j<= evt_num; j+=2) { - - readbytes = 0; - - if(j == 1) /* if current one is a sys event */ - size = header.sys_size; - if(j == 2) /* if current one is a user event */ - size = header.total_size - header.sys_size; - - if(into_file && (events_des[j][grpid][hookid] == NULL || - events_des[j][grpid][hookid]->count <= 0)) { - //no format is provided, dump in hex - buffer = malloc(size); - fread(buffer, size, 1, infp); - fwrite(buffer, size, 1, outfp); - free(buffer); - total_bytes += size; - continue; - } - - events_des[j][grpid][hookid]->flag = 1; - - for(i=0; icount; i++) { - fmt = events_des[j][grpid][hookid]->evt_fmt[i]; - name = events_des[j][grpid][hookid]->evt_names[i]; -#ifdef HAS_MYSQL - if(into_db) { - strcat(sql_col, "`"); - strcat(sql_col, name); - strcat(sql_col, "`,"); - } -#endif - - if(into_file) { - fwrite(name, strlen(name), 1, outfp); - fwrite(":", 1, 1, outfp); - } - if(strncmp(fmt, "INT8", 4)==0) { - c = fgetc_unlocked(infp); - if(into_file) - fprintf(outfp, "%d,", (int8_t)c); - sprintf(tmp_int, "%d,", (int8_t)c); -#ifdef HAS_MYSQL - if(into_db) - strcat(sql_val, tmp_int); -#endif - readbytes+=1; - } else if(strncmp(fmt, "INT16", 5)==0) { - fread(&stemp, 2, 1, infp); - if(into_file) - fprintf(outfp, "%d,", (int16_t)stemp); - sprintf(tmp_int, "%d,", (int16_t)stemp); -#ifdef HAS_MYSQL - if(into_db) - strcat(sql_val, tmp_int); -#endif - readbytes+=2; - } else if(strncmp(fmt, "INT32", 5)==0) { - fread(&ntemp, 4, 1, infp); - if(into_file) - fprintf(outfp, "%d,", (int32_t)ntemp); - snprintf(tmp_int, 20, "%d,", (int32_t)ntemp); -#ifdef HAS_MYSQL - if(into_db) - strcat(sql_val, tmp_int); -#endif - readbytes+=4; - } else if(strncmp(fmt, "INT64", 5)==0) { - fread(&lltemp, 8, 1, infp); - if(into_file) - fprintf(outfp, "%lld,",lltemp); - snprintf(tmp_int, 30, "%lld,", lltemp); -#ifdef HAS_MYSQL - if(into_db) - strcat(sql_val, tmp_int); -#endif - readbytes+=8; - } else if(strncmp(fmt, "STRING", 6)==0) { - -#ifdef HAS_MYSQL - int tmplen=0; - if(into_db) { - tmplen=strlen(sql_val); - sql_val[tmplen++]='"'; - } -#endif - c = fgetc_unlocked(infp); - ++readbytes; - while (c && readbytes < size) { - if(into_file) - fputc_unlocked(c, outfp); -#ifdef HAS_MYSQL - if(into_db) - sql_val[tmplen++]=c; -#endif - c = fgetc_unlocked(infp); - ++readbytes; - } - if(!c) { - if(into_file) - fputc_unlocked(',', outfp); -#ifdef HAS_MYSQL - if(into_db) { - sql_val[tmplen++]='"'; - sql_val[tmplen++]=','; - sql_val[tmplen]='\0'; - } -#endif - continue; - } - else { - b2a_error("error processing STRING\n"); - } - } - } - total_bytes += readbytes; - } - -#ifdef HAS_MYSQL - if(into_db) { - sql_col[strlen(sql_col)-1] = '\0'; - sql_val[strlen(sql_val)-1] = '\0'; - snprintf(sql, 1024, "insert into %d_%d (%s) values (%s)", - grpid, hookid, sql_col, sql_val); - - if(sql_count >= INSERT_THRESHOLD) { - if(mysql_query(&mysql, sqlStatement)) { - b2a_error("Failed exec SQL:\n%s\n, Error:\n%s\n", - sqlStatement, mysql_error(&mysql)); - } - while(!mysql_next_result(&mysql)); - sql_count=0; - sqlStatement[0]='\0'; - } else { - //strncpy(sqlStatement, sql, 2048); - strcat(sqlStatement, sql); - strcat(sqlStatement, ";"); - sql_count++; - } - } -#endif - - return total_bytes; -} diff --git a/runtime/lket/b2a/lket_b2a.h b/runtime/lket/b2a/lket_b2a.h deleted file mode 100644 index 46ca91f6..00000000 --- a/runtime/lket/b2a/lket_b2a.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef _LKET_B2A_H -#define _LKET_B2A_H - -#include - -#ifdef HAS_MYSQL -#include -#endif - -typedef struct _percpu_header { - int32_t seq; - int32_t len; -} percpu_header; - -#define LKET_MAGIC 0xAEFCDB6B - -#define MAX_STRINGLEN 256 - -#define MAX_GRPID 255 -#define MAX_HOOKID 255 -#define MAX_EVT_TYPES 3 - -#define DEFAULT_OUTFILE_NAME "lket.out" - -/* Group ID Definitions */ -int _GROUP_REGEVT = 1; -int _GROUP_PROCESS = 3; -int _GROUP_CPUFREQ = 15; - -/* hookIDs defined inside each group */ -int _HOOKID_REGSYSEVT = 1; -int _HOOKID_REGUSREVT = 3; -int _HOOKID_REGEVTDESC = 5; - -int _HOOKID_PROCESS_SNAPSHOT = 1; -int _HOOKID_PROCESS_EXECVE = 3; -int _HOOKID_PROCESS_FORK = 5; - -//int _HOOKID_INIT_CPUFREQ = 1; -int _HOOKID_SWITCH_CPUFREQ = 1; - -typedef struct _lket_pkt_header { - int16_t total_size; - int16_t sys_size; - int64_t microsecond; - /* tid_pid is (tid<<32|pid) */ - int64_t tid_pid; - /* aggr is the bit-OP of: - (int64_t)current->parent->tgid << 32 | - (int32_t)GroupID << 24 | (int32_t)hookID << 16 | - (int16_t)current->thread_info->cpu << 8 - */ - int64_t aggr; -} __attribute__((packed)) lket_pkt_header; - -#define HDR_TID(ptr) (int32_t)(((ptr)->tid_pid)>>32) -#define HDR_PID(ptr) (int32_t)((ptr)->tid_pid) -#define HDR_PPID(ptr) (int32_t)(((ptr)->aggr)>>32) -#define HDR_GroupID(ptr) (int8_t)(((ptr)->aggr)>>24) -#define HDR_HookID(ptr) (int8_t)(((ptr)->aggr)>>16) -#define HDR_CpuID(ptr) (int8_t)(((ptr)->aggr)>>8) - -#define MAX_FIELDS 32 /* max fields in a record */ -#define MAX_FIELDNAME_LEN 16 /* max len of a field */ - -typedef struct { -#ifdef HAS_MYSQL - GTree *entrytime; -#endif - char evt_fmt[MAX_FIELDS][7]; /* e.g. INT8,STRING,INT16,... */ - char evt_names[MAX_FIELDS][MAX_FIELDNAME_LEN]; /* e.g. protocal,dev_name,buff_len,... */ - char fmt[256]; /* e.g. %1b,%0s,%2b,... */ - char *description; /* a string description of this event, such as "iosyscall.read.entry" */ - int count; /* # of fields */ - int flag; /* a flag indicates whether exists trace data for this event */ -} event_desc; - -/* - * search the lket_init_header structure in a set of input files - */ -static void find_init_header(FILE **fp, const int total_infiles); - -/* - * read the lket_pkt_header structure at the begining of the input file - */ -static int get_pkt_header(FILE *fp, lket_pkt_header *phdr); - -/* - * print the lket_pkt_header structure into the output file - */ -static void print_pkt_header(lket_pkt_header *phdr); - -void register_appname(int i, FILE *fp, lket_pkt_header *phdr); -gint compareFunc(gconstpointer a, gconstpointer b, gpointer user_data); -void destroyTreeData(gpointer data); -void register_evt_desc(FILE *infp, size_t size); -void register_events(int evt_type, FILE *infp, size_t size); -int dump_data(lket_pkt_header header, FILE *infp); -char *get_fmtstr(char *fmt); - -#endif diff --git a/runtime/map.c b/runtime/map.c index 513e27df..a436d7ed 100644 --- a/runtime/map.c +++ b/runtime/map.c @@ -15,7 +15,6 @@ * @brief Implements maps (associative arrays) and lists */ -#include "alloc.c" #include "sym.c" #include "stat-common.c" #include "map-stat.c" diff --git a/runtime/probes.c b/runtime/probes.c index 19539044..6fe844fb 100644 --- a/runtime/probes.c +++ b/runtime/probes.c @@ -25,7 +25,7 @@ void _stp_unregister_jprobes (struct jprobe *probes, int num_probes) int i; for (i = 0; i < num_probes; i++) unregister_jprobe(&probes[i]); - dbug("All jprobes removed\n"); + // dbug("All jprobes removed\n"); } /** Register a group of jprobes. @@ -46,7 +46,7 @@ int _stp_register_jprobes (struct jprobe *probes, int num_probes) ret = -1; /* FIXME */ goto out; } - dbug("inserting jprobe at %s (%p)\n", probes[i].kp.addr, addr); + // dbug("inserting jprobe at %s (%p)\n", probes[i].kp.addr, addr); probes[i].kp.addr = (kprobe_opcode_t *)addr; ret = register_jprobe(&probes[i]); if (ret) @@ -69,7 +69,7 @@ void _stp_unregister_kprobes (struct kprobe *probes, int num_probes) int i; for (i = 0; i < num_probes; i++) unregister_kprobe(&probes[i]); - dbug("All kprobes removed\n"); + // dbug("All kprobes removed\n"); } @@ -83,7 +83,7 @@ void _stp_unregister_kretprobes (struct kretprobe *probes, int num_probes) int i; for (i = 0; i < num_probes; i++) unregister_kretprobe(&probes[i]); - dbug("All return probes removed\n"); + // dbug("All return probes removed\n"); } #endif @@ -104,7 +104,7 @@ int _stp_register_kprobes (struct kprobe *probes, int num_probes) ret = -1; goto out; } - dbug("inserting kprobe at %s (%p)\n", probes[i].addr, addr); + // dbug("inserting kprobe at %s (%p)\n", probes[i].addr, addr); probes[i].addr = (kprobe_opcode_t *)addr; ret = register_kprobe(&probes[i]); if (ret) @@ -136,7 +136,7 @@ int _stp_register_kretprobes (struct kretprobe *probes, int num_probes) ret = -1; /* FIXME */ goto out; } - dbug("inserting kretprobe at %s (%p)\n", probes[i].kp.addr, addr); + // dbug("inserting kretprobe at %s (%p)\n", probes[i].kp.addr, addr); probes[i].kp.addr = (kprobe_opcode_t *)addr; ret = register_kretprobe(&probes[i]); if (ret) diff --git a/runtime/probes/bench/Makefile b/runtime/probes/bench/Makefile deleted file mode 100644 index 9154e3dc..00000000 --- a/runtime/probes/bench/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: ttest itest - -ttest: ttest.c - gcc -Wall -O3 -o ttest ttest.c - -itest: itest.c - gcc -Wall -O3 -o itest itest.c - -clean: - /bin/rm -f itest ttest stpd_cpu* xxx* diff --git a/runtime/runtime.h b/runtime/runtime.h index 318d3038..b9a9c778 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -76,7 +76,6 @@ static struct #include "io.c" #include "arith.c" #include "copy.c" -#include "sym.h" #include "sym.c" #ifdef STP_PERFMON #include "perf.c" diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 186b2ad4..3ba99201 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * x86_64 stack tracing functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * * 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 @@ -8,13 +8,38 @@ * later version. */ -static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) +// todo: don't use unwinder for kernel if CONFIG_FRAME + +/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ +static void _stp_stack_print_fallback(unsigned long stack, int verbose) { - unsigned long *stack = (unsigned long *)REG_SP(regs); unsigned long addr; - while ((long)stack & (THREAD_SIZE-1)) { - addr = *stack++; - _stp_func_print(addr, verbose, 1); + while (stack & (THREAD_SIZE - 1)) { + if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) { + /* cannot access stack. give up. */ + return; + } + _stp_func_print(addr, verbose, 0); + stack++; + } +} + +static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels) +{ + struct unwind_frame_info info; + arch_unw_init_frame_info(&info, regs); + + /* we haven't actually executed the instruction at the IP yet. */ + UNW_PC(&info) -= 1; + + while (!arch_unw_user_mode(&info)) { + int ret = unwind(&info); + dbug_unwind(1, "ret=%d PC=%lx\n", ret, UNW_PC(&info)); + if (ret < 0) { + _stp_stack_print_fallback(UNW_SP(&info), verbose); + break; + } + _stp_func_print(UNW_PC(&info), verbose, 1); } } diff --git a/runtime/stack.c b/runtime/stack.c index 9c01d65c..e338f587 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Stack tracing functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * Copyright (C) 2005 Intel Corporation. * * This file is part of systemtap, and is free software. You can @@ -23,6 +23,7 @@ #include "sym.c" #include "regs.h" +#include "unwind.c" #define MAXBACKTRACE 20 diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 2e0c3c5c..1dcb6b00 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -27,7 +27,7 @@ static void sigproc(int signum) return; send_request(STP_EXIT, NULL, 0); } else if (signum == SIGQUIT) - cleanup_and_exit(2); + cleanup_and_exit(2); else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) send_request(STP_EXIT, NULL, 0); } @@ -40,7 +40,7 @@ static void setup_main_signals(int cleanup) if (cleanup == 0) { a.sa_handler = sigproc; sigaction(SIGCHLD, &a, NULL); - } else + } else a.sa_handler = SIG_IGN; sigaction(SIGINT, &a, NULL); sigaction(SIGTERM, &a, NULL); @@ -48,7 +48,6 @@ static void setup_main_signals(int cleanup) sigaction(SIGQUIT, &a, NULL); } - /* * start_cmd forks the command given on the command line * with the "-c" option. It will not exec that command @@ -75,7 +74,7 @@ void start_cmd(void) a.sa_handler = SIG_IGN; sigaction(SIGINT, &a, NULL); - dbug (1, "execing target_cmd %s\n", target_cmd); + dbug(1, "execing target_cmd %s\n", target_cmd); if ((pid = fork()) < 0) { _perr("fork"); exit(1); @@ -86,8 +85,8 @@ void start_cmd(void) sigaction(SIGINT, &a, NULL); /* commands we fork need to run at normal priority */ - setpriority (PRIO_PROCESS, 0, 0); - + setpriority(PRIO_PROCESS, 0, 0); + /* wait here until signaled */ sigwait(&usrset, &signum); @@ -107,11 +106,11 @@ void system_cmd(char *cmd) { pid_t pid; - dbug (2, "system %s\n", cmd); + dbug(2, "system %s\n", cmd); if ((pid = fork()) < 0) { _perr("fork"); } else if (pid == 0) { - setpriority (PRIO_PROCESS, 0, 0); + setpriority(PRIO_PROCESS, 0, 0); if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) perr("%s", cmd); _exit(1); @@ -128,7 +127,7 @@ static void read_buffer_info(void) if (!use_old_transport) return; - if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) + if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) return; if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) @@ -152,7 +151,6 @@ static void read_buffer_info(void) return; } - /** * init_stapio - initialize the app * @print_summary: boolean, print summary or not at end of run @@ -177,7 +175,7 @@ int init_stapio(void) if (init_oldrelayfs() < 0) { close_ctl_channel(); return -1; - } + } } else { if (init_relayfs() < 0) { close_ctl_channel(); @@ -192,7 +190,6 @@ int init_stapio(void) if (target_cmd) start_cmd(); - return 0; } @@ -202,7 +199,7 @@ int init_stapio(void) * 2 - disconnected * 3 - initialized */ -void cleanup_and_exit (int closed) +void cleanup_and_exit(int closed) { pid_t err; static int exiting = 0; @@ -219,7 +216,7 @@ void cleanup_and_exit (int closed) err = waitpid(-1, NULL, WNOHANG); if (err >= 0) err("\nWaiting for processes to exit\n"); - while(wait(NULL) > 0) ; + while (wait(NULL) > 0) ; if (use_old_transport) close_oldrelayfs(closed == 2); @@ -230,8 +227,7 @@ void cleanup_and_exit (int closed) close_ctl_channel(); if (initialized == 2 && closed == 2) { - err("\nDisconnecting from systemtap module.\n" \ - "To reconnect, type \"staprun -A %s\"\n", modname); + err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname); } else if (initialized) closed = 3; else @@ -247,7 +243,7 @@ int stp_main_loop(void) { ssize_t nb; void *data; - int type; + uint32_t type; FILE *ofp = stdout; char recvbuf[8196]; @@ -257,80 +253,93 @@ int stp_main_loop(void) dbug(2, "in main loop\n"); send_request(STP_READY, NULL, 0); - while (1) { /* handle messages from control channel */ + while (1) { /* handle messages from control channel */ nb = read(control_channel, recvbuf, sizeof(recvbuf)); if (nb <= 0) { if (errno != EINTR) _perr("Unexpected EOF in read (nb=%ld)", (long)nb); continue; } - - type = *(int *)recvbuf; - data = (void *)(recvbuf + sizeof(int)); - switch (type) { + type = *(uint32_t *)recvbuf; + data = (void *)(recvbuf + sizeof(uint32_t)); + nb -= sizeof(uint32_t); + + switch (type) { #ifdef STP_OLD_TRANSPORT case STP_REALTIME_DATA: - { - ssize_t bw = write(out_fd[0], data, nb - sizeof(int)); - if (bw >= 0 && bw != (nb - (ssize_t)sizeof(int))) { - nb = nb - bw; - bw = write(out_fd[0], data, nb - sizeof(int)); - } - if (bw != (nb - (ssize_t)sizeof(int))) { - _perr("write error (nb=%ld)", (long)nb); - cleanup_and_exit(1); + { + ssize_t bw = write(out_fd[0], data, nb); + if (bw >= 0 && bw != nb) { + nb = nb - bw; + bw = write(out_fd[0], data, nb); + } + if (bw != nb) { + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(1); + } + break; } - break; - } #endif case STP_OOB_DATA: - fputs ((char *)data, stderr); - break; - case STP_EXIT: - { - /* module asks us to unload it and exit */ - int *closed = (int *)data; - dbug(2, "got STP_EXIT, closed=%d\n", *closed); - cleanup_and_exit(*closed); - break; - } - case STP_START: - { - struct _stp_msg_start *t = (struct _stp_msg_start *)data; - dbug(2, "probe_start() returned %d\n", t->res); - if (t->res < 0) { - if (target_cmd) - kill (target_pid, SIGKILL); - cleanup_and_exit(1); - } else if (target_cmd) - kill (target_pid, SIGUSR1); + fputs((char *)data, stderr); break; - } + case STP_EXIT: + { + /* module asks us to unload it and exit */ + int *closed = (int *)data; + dbug(2, "got STP_EXIT, closed=%d\n", *closed); + cleanup_and_exit(*closed); + break; + } + case STP_START: + { + struct _stp_msg_start *t = (struct _stp_msg_start *)data; + dbug(2, "probe_start() returned %d\n", t->res); + if (t->res < 0) { + if (target_cmd) + kill(target_pid, SIGKILL); + cleanup_and_exit(1); + } else if (target_cmd) + kill(target_pid, SIGUSR1); + break; + } case STP_SYSTEM: - { - struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; - dbug(2, "STP_SYSTEM: %s\n", c->cmd); - system_cmd(c->cmd); - break; - } + { + struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; + dbug(2, "STP_SYSTEM: %s\n", c->cmd); + system_cmd(c->cmd); + break; + } case STP_TRANSPORT: - { - struct _stp_msg_start ts; - if (use_old_transport) { - if (init_oldrelayfs() < 0) - cleanup_and_exit(1); - } else { - if (init_relayfs() < 0) - cleanup_and_exit(1); + { + struct _stp_msg_start ts; + if (use_old_transport) { + if (init_oldrelayfs() < 0) + cleanup_and_exit(1); + } else { + if (init_relayfs() < 0) + cleanup_and_exit(1); + } + ts.target = target_pid; + initialized = 2; + send_request(STP_START, &ts, sizeof(ts)); + if (load_only) + cleanup_and_exit(2); + break; + } + case STP_UNWIND: + { + int len; + char *ptr = (char *)data; + while (nb > 0) { + send_unwind_data(ptr); + len = strlen(ptr) + 1; + ptr += len; + nb -= len; + } + break; } - ts.target = target_pid; - initialized = 2; - send_request(STP_START, &ts, sizeof(ts)); - if (load_only) - cleanup_and_exit(2); - break; - } default: err("WARNING: ignored message of type %d\n", (type)); } diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index f4e67fdb..8db2ac5b 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -181,8 +181,6 @@ static void cleanup(int rc) if (setpriority (PRIO_PROCESS, 0, 0) < 0) _perr("setpriority"); - stop_symbol_thread(); - /* rc == 2 means disconnected */ if (rc == 2) return; @@ -278,7 +276,6 @@ int main(int argc, char **argv) exit(1); setup_staprun_signals(); - start_symbol_thread(); rc = run_stapio(argv); cleanup(rc); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 1128fb4c..08797a37 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -118,8 +118,7 @@ int init_stapio(void); int stp_main_loop(void); int send_request(int type, void *data, int len); void cleanup_and_exit (int); -int do_module(void *); -int do_kernel_symbols(void); +void send_unwind_data(const char *name); int init_ctl_channel(int); void close_ctl_channel(void); int init_relayfs(void); diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index 34e12c25..b95a9a5a 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -401,95 +401,3 @@ int check_permissions(void) * is in that directory. */ return check_path(); } - -pthread_t symbol_thread_id = (pthread_t)0; -int kernel_ptr_size = 0; - -/* Symbol handling thread */ -void *handle_symbols(void __attribute__((unused)) *arg) -{ - ssize_t nb; - void *data; - int32_t type; - char recvbuf[8192]; - - dbug(2, "waiting for symbol requests\n"); - - /* handle messages from control channel */ - while (1) { - nb = read(control_channel, recvbuf, sizeof(recvbuf)); - if (nb <= 0) { - if (errno != EINTR) - _perr("Unexpected EOF in read (nb=%ld)", (long)nb); - continue; - } - - type = *(int32_t *)recvbuf; - data = (void *)(recvbuf + sizeof(int32_t)); - - switch (type) { - case STP_MODULE: - { - dbug(2, "STP_MODULES request received\n"); - if (do_module(data) < 0) - goto done; - break; - } - case STP_SYMBOLS: - { - struct _stp_msg_symbol *req = (struct _stp_msg_symbol *)data; - dbug(2, "STP_SYMBOLS request received\n"); - if (req->endian != 0x1234) { - err("ERROR: staprun is compiled with different endianess than the kernel!\n"); - goto done; - } - kernel_ptr_size = req->ptr_size; - if (kernel_ptr_size != 4 && kernel_ptr_size != 8) { - err("ERROR: invalid kernel pointer size %d\n", kernel_ptr_size); - goto done; - } - if (do_kernel_symbols() < 0) - goto done; - break; - } - default: - err("WARNING: ignored message of type %d\n", (type)); - } - } - -done: - /* signal stapio we're done */ - kill(0, SIGINT); - - return NULL; -} - -void start_symbol_thread(void) -{ - int status; - - /* create symbol control channel */ - status = do_cap(CAP_DAC_OVERRIDE, init_ctl_channel, 1); - drop_cap(CAP_DAC_OVERRIDE); - if (status < 0) { - err("Failed to initialize control channel.\n"); - exit(1); - } - status = pthread_create(&symbol_thread_id, NULL, handle_symbols, NULL); - if (status) { - perr("Failed to create symbol thread.\n"); - exit(1); - } -} - -void stop_symbol_thread(void) -{ - - if (symbol_thread_id) { - dbug(2, "Stopping symbol thread.\n"); - pthread_cancel(symbol_thread_id); - pthread_join(symbol_thread_id, NULL); - } - close_ctl_channel(); -} - diff --git a/runtime/staprun/unwind_data.c b/runtime/staprun/unwind_data.c new file mode 100644 index 00000000..ed27cc20 --- /dev/null +++ b/runtime/staprun/unwind_data.c @@ -0,0 +1,97 @@ +/* -*- linux-c -*- + * Unwind data functions for staprun. + * + * Copyright (C) 2008 Red Hat Inc. + * + * 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 "staprun.h" +#include +#include + +static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug"; +static char *debuginfo_path = debuginfo_path_arr; +static const Dwfl_Callbacks kernel_callbacks = { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + .find_elf = dwfl_linux_kernel_find_elf, + .section_address = dwfl_linux_kernel_module_section_address, +}; + +void *get_module_unwind_data(Dwfl * dwfl, const char *name, int *len) +{ + Dwarf_Addr bias = 0; + Dwarf *dw; + GElf_Ehdr *ehdr, ehdr_mem; + GElf_Shdr *shdr, shdr_mem; + Elf_Scn *scn = NULL; + Elf_Data *data = NULL; + + Dwfl_Module *mod = dwfl_report_module(dwfl, name, 0, 0); + dwfl_report_end(dwfl, NULL, NULL); + dw = dwfl_module_getdwarf(mod, &bias); + Elf *elf = dwarf_getelf(dw); + ehdr = gelf_getehdr(elf, &ehdr_mem); + while ((scn = elf_nextscn(elf, scn))) { + shdr = gelf_getshdr(scn, &shdr_mem); + if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), ".debug_frame") == 0) { + data = elf_rawdata(scn, NULL); + break; + } + } + + if (data == NULL) { + *len = 0; + dbug(2, "module %s returns NULL\n", name); + return NULL; + } + dbug(2, "module %s returns %d\n", name, (int)data->d_size); + *len = data->d_size; + return data->d_buf; +} + +void send_unwind_data(const char *name) +{ + struct _stp_msg_unwind *un; + int unwind_data_len = 0; + void *unwind_data = NULL; + char *buf; + + dbug(2, "module %s\n", name); + if (strcmp(name, "*")) { + Dwfl *dwfl = dwfl_begin(&kernel_callbacks); + + if (name[0] == 0) + unwind_data = get_module_unwind_data(dwfl, "kernel", &unwind_data_len); + else + unwind_data = get_module_unwind_data(dwfl, name, &unwind_data_len); + + /* yuck */ + buf = (char *)malloc(unwind_data_len + sizeof(*un) + sizeof(uint32_t)); + if (!buf) { + err("malloc failed\n"); + return; + } + memcpy(buf + sizeof(*un) + sizeof(uint32_t), unwind_data, unwind_data_len); + dwfl_end(dwfl); + } else { + buf = (char *)malloc(sizeof(*un) + sizeof(uint32_t)); + if (!buf) { + err("malloc failed\n"); + return; + } + } + + un = (struct _stp_msg_unwind *)(buf + sizeof(uint32_t)); + strncpy(un->name, name, sizeof(un->name)); + un->unwind_len = unwind_data_len; + *(uint32_t *) buf = STP_UNWIND; + + /* send unwind data */ + if (write(control_channel, buf, unwind_data_len + sizeof(*un) + sizeof(uint32_t)) <= 0) + err("write failed\n"); +} diff --git a/runtime/sym.c b/runtime/sym.c index 3c2f859a..3d5ff01d 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -33,7 +33,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi return 0; } - dbug(DEBUG_SYMBOLS, "%s, %s, %lx\n", module, section, offset); + dbug_sym(1, "%s, %s, %lx\n", module, section, offset); STP_RLOCK_MODULES; if (!module || !strcmp(section, "") /* absolute, unrelocated address */ @@ -47,7 +47,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi if (!strcmp(module, last->name) && !strcmp(section, last_sec->symbol)) { offset += last_sec->addr; STP_RUNLOCK_MODULES; - dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); + dbug_sym(1, "offset = %lx\n", offset); return offset; } } @@ -72,7 +72,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi if (!strcmp(section, last_sec->symbol)) { offset += last_sec->addr; STP_RUNLOCK_MODULES; - dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); + dbug_sym(1, "offset = %lx\n", offset); return offset; } } diff --git a/runtime/sym.h b/runtime/sym.h index b124882a..631a5bbf 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -7,8 +7,8 @@ * later version. */ -#ifndef _STAP_SYMBOLS_H_ -#define _STAP_SYMBOLS_H_ +#ifndef _STP_SYM_H_ +#define _STP_SYM_H_ #define STP_MODULE_NAME_LEN 64 @@ -16,11 +16,6 @@ struct _stp_symbol { unsigned long addr; const char *symbol; }; -struct stap_symbol { - unsigned long addr; - const char *symbol; - const char *module; -}; DEFINE_RWLOCK(_stp_module_lock); #define STP_RLOCK_MODULES read_lock_irqsave(&_stp_module_lock, flags) @@ -50,8 +45,14 @@ struct _stp_module { /* how many sections this module has */ uint32_t num_sections; - /* how the symbol_data below was allocated */ - int32_t allocated; /* 0 = kmalloc, 1 = vmalloc */ + /* how the data below was allocated */ + /* 0 = kmalloc, 1 = vmalloc */ + struct { + unsigned symbols :1; + unsigned symbol_data :1; + unsigned unwind_data :1; + unsigned unwind_hdr :1; + } allocated; struct _stp_symbol *sections; @@ -63,7 +64,10 @@ struct _stp_module { /* the stack unwind data for this module */ void *unwind_data; + void *unwind_hdr; uint32_t unwind_data_len; + uint32_t unwind_hdr_len; + uint32_t unwind_is_ehframe; /* unwind data comes from .eh_frame */ rwlock_t lock; /* lock while unwinding is happening */ }; @@ -83,4 +87,4 @@ int _stp_num_modules = 0; unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset); static struct _stp_module *_stp_get_unwind_info (unsigned long addr); -#endif /* _STAP_SYMBOLS_H_ */ +#endif /* _STP_SYM_H_ */ diff --git a/runtime/tests/Makefile b/runtime/tests/Makefile deleted file mode 100644 index 4e744d25..00000000 --- a/runtime/tests/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -tests: - tclsh all.tcl - diff --git a/runtime/tests/agg/Makefile b/runtime/tests/agg/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/agg/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/maps/Makefile b/runtime/tests/maps/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/maps/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/math/Makefile b/runtime/tests/math/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/math/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/pmaps/Makefile b/runtime/tests/pmaps/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/pmaps/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/string/Makefile b/runtime/tests/string/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/string/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 6a5b272d..ed7725fa 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -14,80 +14,31 @@ static int _stp_current_buffers = STP_DEFAULT_BUFFERS; static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; -static struct list_head _stp_sym_ready_q; DEFINE_SPINLOCK(_stp_ctl_ready_lock); -DEFINE_SPINLOCK(_stp_sym_ready_lock); -static ssize_t _stp_sym_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - static int saved_type = 0; - int type; - - if (count < sizeof(int32_t)) - return 0; - - /* Allow sending of packet type followed by data in the next packet. */ - if (count == sizeof(int32_t)) { - if (get_user(saved_type, (int __user *)buf)) - return -EFAULT; - return count; - } else if (saved_type) { - type = saved_type; - saved_type = 0; - } else { - if (get_user(type, (int __user *)buf)) - return -EFAULT; - count -= sizeof(int); - buf += sizeof(int); - } - -#if DEBUG_TRANSPORT > 0 - if (type < STP_MAX_CMD) - _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); -#endif - - switch (type) { - case STP_SYMBOLS: - count = _stp_do_symbols(buf, count); - break; - case STP_MODULE: - if (count > 1) - count = _stp_do_module(buf, count); - else { - /* count == 1 indicates end of initial modules list */ - _stp_ctl_send(STP_TRANSPORT, NULL, 0); - } - break; - case STP_EXIT: - _stp_exit_flag = 1; - break; - default: - errk("invalid symbol command type %d\n", type); - return -EINVAL; - } - - return count; -} static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - int type; + u32 type; static int started = 0; - if (count < sizeof(int)) + if (count < sizeof(u32)) return 0; - if (get_user(type, (int __user *)buf)) + if (get_user(type, (u32 __user *)buf)) return -EFAULT; -#if DEBUG_TRANSPORT > 0 + count -= sizeof(u32); + buf += sizeof(u32); + +#ifdef DEBUG_TRANS if (type < STP_MAX_CMD) _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); #endif - count -= sizeof(int); - buf += sizeof(int); - switch (type) { + case STP_UNWIND: + _stp_do_unwind_data(buf, count); + break; case STP_START: if (started == 0) { struct _stp_msg_start st; @@ -110,7 +61,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz #endif case STP_READY: /* request symbolic information */ - _stp_ask_for_symbols(); + /* _stp_ask_for_symbols(); */ break; default: @@ -121,8 +72,6 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz return count; } -#define STP_CTL_BUFFER_SIZE 256 - struct _stp_buffer { struct list_head list; int len; @@ -131,9 +80,8 @@ struct _stp_buffer { }; static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq); -static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq); -#if DEBUG_TRANSPORT > 0 +#ifdef DEBUG_TRANS static void _stp_ctl_write_dbug(int type, void *data, int len) { char buf[64]; @@ -155,20 +103,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; - default: - _dbug("ERROR: unknown message type: %d\n", type); - break; - } -} -static void _stp_sym_write_dbug(int type, void *data, int len) -{ - switch (type) { - case STP_SYMBOLS: - _dbug("sending STP_SYMBOLS\n"); - break; - case STP_MODULE: - _dbug("sending STP_MODULE\n"); - break; + case STP_UNWIND: + snprintf(buf, sizeof(buf), "%s", (char *)data); + _dbug("sending STP_UNWIND %s [len=%d]\n", buf, len); default: _dbug("ERROR: unknown message type: %d\n", type); break; @@ -181,7 +118,7 @@ static int _stp_ctl_write(int type, void *data, unsigned len) struct _stp_buffer *bptr; unsigned long flags; -#if DEBUG_TRANSPORT > 0 +#ifdef DEBUG_TRANS _stp_ctl_write_dbug(type, data, len); #endif @@ -206,96 +143,19 @@ static int _stp_ctl_write(int type, void *data, unsigned len) return len; } -static int _stp_sym_write(int type, void *data, unsigned len) -{ - struct _stp_buffer *bptr; - unsigned long flags; - -#if DEBUG_TRANSPORT > 0 - _stp_sym_write_dbug(type, data, len); -#endif - - /* make sure we won't overflow the buffer */ - if (unlikely(len > STP_CTL_BUFFER_SIZE)) - return 0; - - /* get a buffer from the free pool */ - bptr = _stp_mempool_alloc(_stp_pool_q); - if (unlikely(bptr == NULL)) - return -1; - - bptr->type = type; - memcpy(bptr->buf, data, len); - bptr->len = len; - - /* put it on the pool of ready buffers */ - spin_lock_irqsave(&_stp_sym_ready_lock, flags); - list_add_tail(&bptr->list, &_stp_sym_ready_q); - spin_unlock_irqrestore(&_stp_sym_ready_lock, flags); - - /* OK, it's queued. Now signal any waiters. */ - wake_up_interruptible(&_stp_sym_wq); - - return len; -} - /* send commands with timeout and retry */ static int _stp_ctl_send(int type, void *data, int len) { int err, trylimit = 50; - kbug(DEBUG_TRANSPORT, "ctl_send: type=%d len=%d\n", type, len); - if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) { - while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--) - msleep(5); - } else { - while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--) - msleep(5); - if (err > 0) - wake_up_interruptible(&_stp_ctl_wq); - } - kbug(DEBUG_TRANSPORT, "returning %d\n", err); + dbug_trans(1, "ctl_send: type=%d len=%d\n", type, len); + while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--) + msleep(5); + if (err > 0) + wake_up_interruptible(&_stp_ctl_wq); + dbug_trans(1, "returning %d\n", err); return err; } -static ssize_t _stp_sym_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct _stp_buffer *bptr; - int len; - unsigned long flags; - - /* wait for nonempty ready queue */ - spin_lock_irqsave(&_stp_sym_ready_lock, flags); - while (list_empty(&_stp_sym_ready_q)) { - spin_unlock_irqrestore(&_stp_sym_ready_lock, flags); - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - if (wait_event_interruptible(_stp_sym_wq, !list_empty(&_stp_sym_ready_q))) - return -ERESTARTSYS; - spin_lock_irqsave(&_stp_sym_ready_lock, flags); - } - - /* get the next buffer off the ready list */ - bptr = (struct _stp_buffer *)_stp_sym_ready_q.next; - list_del_init(&bptr->list); - spin_unlock_irqrestore(&_stp_sym_ready_lock, flags); - - /* write it out */ - len = bptr->len + 4; - if (len > count || copy_to_user(buf, &bptr->type, len)) { - /* now what? We took it off the queue then failed to send it */ - /* we can't put it back on the queue because it will likely be out-of-order */ - /* fortunately this should never happen */ - /* FIXME need to mark this as a transport failure */ - errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len); - return -EFAULT; - } - - /* put it on the pool of free buffers */ - _stp_mempool_free(bptr); - - return len; -} - static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct _stp_buffer *bptr; @@ -335,29 +195,10 @@ static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t cou return len; } -static int _stp_sym_opens = 0; -static int _stp_sym_open_cmd(struct inode *inode, struct file *file) -{ - /* only allow one reader */ - if (_stp_sym_opens) - return -1; - - _stp_sym_opens++; - return 0; -} - -static int _stp_sym_close_cmd(struct inode *inode, struct file *file) -{ - if (_stp_sym_opens) - _stp_sym_opens--; - return 0; -} - static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) { if (_stp_attached) return -1; - _stp_attach(); return 0; } @@ -377,16 +218,7 @@ static struct file_operations _stp_ctl_fops_cmd = { .release = _stp_ctl_close_cmd, }; -static struct file_operations _stp_sym_fops_cmd = { - .owner = THIS_MODULE, - .read = _stp_sym_read_cmd, - .write = _stp_sym_write_cmd, - .open = _stp_sym_open_cmd, - .release = _stp_sym_close_cmd, -}; - static struct dentry *_stp_cmd_file = NULL; -static struct dentry *_stp_sym_file = NULL; static int _stp_register_ctl_channel(void) { @@ -400,7 +232,6 @@ static int _stp_register_ctl_channel(void) } INIT_LIST_HEAD(&_stp_ctl_ready_q); - INIT_LIST_HEAD(&_stp_sym_ready_q); /* allocate buffers */ _stp_pool_q = _stp_mempool_init(sizeof(struct _stp_buffer), STP_DEFAULT_BUFFERS); @@ -415,15 +246,9 @@ static int _stp_register_ctl_channel(void) _stp_cmd_file->d_inode->i_uid = _stp_uid; _stp_cmd_file->d_inode->i_gid = _stp_gid; - /* create [debugfs]/systemtap/module_name/.symbols */ - _stp_sym_file = debugfs_create_file(".symbols", 0600, _stp_utt->dir, NULL, &_stp_sym_fops_cmd); - if (_stp_sym_file == NULL) - goto err0; return 0; err0: - if (_stp_cmd_file) - debugfs_remove(_stp_cmd_file); _stp_mempool_destroy(_stp_pool_q); errk("Error creating systemtap debugfs entries.\n"); return -1; @@ -432,16 +257,10 @@ err0: static void _stp_unregister_ctl_channel(void) { struct list_head *p, *tmp; - if (_stp_sym_file) - debugfs_remove(_stp_sym_file); if (_stp_cmd_file) debugfs_remove(_stp_cmd_file); /* Return memory to pool and free it. */ - list_for_each_safe(p, tmp, &_stp_sym_ready_q) { - list_del(p); - _stp_mempool_free(p); - } list_for_each_safe(p, tmp, &_stp_ctl_ready_q) { list_del(p); _stp_mempool_free(p); diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 2afea1c9..750e1994 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -161,7 +161,7 @@ struct _stp_buffer { struct list_head list; int len; int type; - char buf[STP_BUFFER_SIZE]; + char buf[STP_CTL_BUFFER_SIZE]; }; static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq); diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 8c453a55..6406d6ad 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -12,8 +12,8 @@ * lib/sort.c of kernel 2.6.22-rc5. It was written by Matt Mackall. */ -#ifndef _SYMBOLS_C_ -#define _SYMBOLS_C_ +#ifndef _STP_SYMBOLS_C_ +#define _STP_SYMBOLS_C_ #include "../sym.h" static char *_stp_symbol_data = NULL; @@ -21,17 +21,12 @@ static int _stp_symbol_state = 0; static char *_stp_module_data = NULL; static int _stp_module_state = 0; - /* these are all the symbol types we are interested in */ static int _stp_sym_type_ok(int type) { - switch (type) { - case 'T': - case 't': + /* we only care about function symbols, which are in the text section */ + if (type == 'T' || type == 't') return 1; - default: - return 0; - } return 0; } @@ -41,10 +36,10 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize) { unsigned int i; unsigned num = 0, datasize = 0; - for (i=0; i < m->num_symtab; i++) { + for (i = 0; i < m->num_symtab; i++) { char *str = (char *)(m->strtab + m->symtab[i].st_name); if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) { - datasize += strlen(str)+1; + datasize += strlen(str) + 1; num++; } } @@ -52,19 +47,23 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize) return num; } -/* allocate space for a module and symbols */ -static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, unsigned unwindsize) +/* allocate space for a module, sections, and symbols */ +static struct _stp_module *_stp_alloc_module(unsigned sectsize, unsigned num, unsigned datasize) { struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); if (mod == NULL) goto bad; + mod->sections = (struct _stp_symbol *)_stp_kmalloc(sectsize); + if (mod->sections == NULL) + goto bad; + mod->symbols = (struct _stp_symbol *)_stp_kmalloc(num * sizeof(struct _stp_symbol)); if (mod->symbols == NULL) { mod->symbols = (struct _stp_symbol *)_stp_vmalloc(num * sizeof(struct _stp_symbol)); if (mod->symbols == NULL) goto bad; - mod->allocated = 1; + mod->allocated.symbols = 1; } mod->symbol_data = _stp_kmalloc(datasize); @@ -72,91 +71,63 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, u mod->symbol_data = _stp_vmalloc(datasize); if (mod->symbol_data == NULL) goto bad; - mod->allocated |= 2; + mod->allocated.symbol_data = 1; } - mod->unwind_data = _stp_kmalloc(unwindsize); - if (mod->unwind_data == NULL) { - mod->unwind_data = _stp_vmalloc(unwindsize); - if (mod->unwind_data == NULL) - goto bad; - mod->allocated |= 4; - } - mod->num_symbols = num; return mod; bad: if (mod) { + if (mod->sections) + _stp_kfree(mod->sections); if (mod->symbols) { - if (mod->allocated & 1) + if (mod->allocated.symbols) _stp_vfree(mod->symbols); else _stp_kfree(mod->symbols); - mod->symbols = NULL; } - if (mod->symbol_data) { - if (mod->allocated & 2) - _stp_vfree(mod->symbol_data); - else - _stp_kfree(mod->symbol_data); - mod->symbol_data = NULL; - } - _stp_kfree(mod); - if (mod->symbols) { - if (mod->allocated & 1) - _stp_vfree(mod->symbols); - else - _stp_kfree(mod->symbols); - mod->symbols = NULL; - } - _stp_kfree(mod); + _stp_kfree(mod); } return NULL; } -static struct _stp_module * _stp_alloc_module_from_module (struct module *m, uint32_t unwind_len) -{ - unsigned datasize, num = _stp_get_sym_sizes(m, &datasize); - return _stp_alloc_module(num, datasize, unwind_len); -} - static void _stp_free_module(struct _stp_module *mod) { /* The module write lock is held. Any prior readers of this */ /* module's data will have read locks and need to finish before */ /* the memory is freed. */ write_lock(&mod->lock); - write_unlock(&mod->lock); /* there will be no more readers */ + write_unlock(&mod->lock); /* there will be no more readers */ - /* free symbol memory */ - if (mod->symbols) { - if (mod->allocated & 1) - _stp_vfree(mod->symbols); - else - _stp_kfree(mod->symbols); - mod->symbols = NULL; - } + /* Free symbol memory */ + /* If symbol_data wasn't allocated, then symbols weren't either. */ if (mod->symbol_data) { - if (mod->allocated & 2) + if (mod->symbols) { + if (mod->allocated.symbols) + _stp_vfree(mod->symbols); + else + _stp_kfree(mod->symbols); + } + if (mod->allocated.symbol_data) _stp_vfree(mod->symbol_data); else _stp_kfree(mod->symbol_data); - mod->symbol_data = NULL; - } if (mod->unwind_data) { - if (mod->allocated & 4) + if (mod->allocated.unwind_data) _stp_vfree(mod->unwind_data); else _stp_kfree(mod->unwind_data); - mod->unwind_data = NULL; - } - if (mod->sections) { - _stp_kfree(mod->sections); - mod->sections = NULL; + if (mod->unwind_hdr) { + if (mod->allocated.unwind_hdr) + _stp_vfree(mod->unwind_hdr); + else + _stp_kfree(mod->unwind_hdr); } + if (mod->sections) + _stp_kfree(mod->sections); /* free module memory */ _stp_kfree(mod); @@ -168,7 +139,7 @@ static void _stp_del_module(struct _stp_module *mod) { int i, num; - // kbug(DEBUG_SYMBOLS, "deleting %s\n", mod->name); + dbug_sym(1, "deleting module %s\n", mod->name); /* signal relocation code to clear its cache */ _stp_module_relocate((char *)-1, NULL, 0); @@ -181,15 +152,15 @@ static void _stp_del_module(struct _stp_module *mod) if (num >= _stp_num_modules) return; - for (i = num; i < _stp_num_modules-1; i++) - _stp_modules[i] = _stp_modules[i+1]; + for (i = num; i < _stp_num_modules - 1; i++) + _stp_modules[i] = _stp_modules[i + 1]; for (num = 0; num < _stp_num_modules; num++) { if (_stp_modules_by_addr[num] == mod) break; } - for (i = num; i < _stp_num_modules-1; i++) - _stp_modules_by_addr[i] = _stp_modules_by_addr[i+1]; + for (i = num; i < _stp_num_modules - 1; i++) + _stp_modules_by_addr[i] = _stp_modules_by_addr[i + 1]; _stp_num_modules--; @@ -197,10 +168,8 @@ static void _stp_del_module(struct _stp_module *mod) } static void _stp_free_modules(void) -{ +{ int i; - unsigned long flags; - /* This only happens when the systemtap module unloads */ /* so there is no need for locks. */ for (i = _stp_num_modules - 1; i >= 0; i--) @@ -208,82 +177,120 @@ static void _stp_free_modules(void) } static unsigned long _stp_kallsyms_lookup_name(const char *name); +static void _stp_create_unwind_hdr(struct _stp_module *m); + +extern unsigned _stp_num_kernel_symbols; +extern struct _stp_symbol _stp_kernel_symbols[]; -/* process the KERNEL symbols */ -static int _stp_do_symbols(const char __user *buf, int count) +/* initialize the kernel symbols */ +static int _stp_init_kernel_symbols(void) { - struct _stp_symbol *s; - unsigned datasize, num, unwindsize; + _stp_modules[0] = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); + if (_stp_modules[0] == NULL) { + errk("cannot allocate memory\n"); + return -EFAULT; + } + _stp_modules[0]->symbols = _stp_kernel_symbols; + _stp_modules[0]->num_symbols = _stp_num_kernel_symbols; + rwlock_init(&_stp_modules[0]->lock); + _stp_num_modules = 1; + + /* Note: this mapping is used by kernel/_stext pseudo-relocations. */ + _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); + _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); + _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text; + _stp_modules_by_addr[0] = _stp_modules[0]; + return 0; +} + +static void _stp_do_unwind_data(const char __user *buf, size_t count) +{ + u64 unwind_len; + unsigned long flags; + char name[STP_MODULE_NAME_LEN]; int i; + struct _stp_module *m; - switch (_stp_symbol_state) { - case 0: - if (count != sizeof(struct _stp_msg_symbol_hdr)) { - errk("count=%d\n", count); - return -EFAULT; - } - if (get_user(num, (unsigned __user *)buf)) - return -EFAULT; - if (get_user(datasize, (unsigned __user *)(buf+4))) - return -EFAULT; - if (get_user(unwindsize, (unsigned __user *)(buf+8))) - return -EFAULT; - dbug(DEBUG_UNWIND, "num=%d datasize=%d unwindsize=%d\n", num, datasize, unwindsize); - - _stp_modules[0] = _stp_alloc_module(num, datasize, unwindsize); - if (_stp_modules[0] == NULL) { - errk("cannot allocate memory\n"); - return -EFAULT; + dbug_unwind(1, "got unwind data, count=%d\n", count); + + if (count < STP_MODULE_NAME_LEN + sizeof(u64)) { + dbug_unwind(1, "unwind message too short\n"); + return; + } + if (strncpy_from_user(name, buf, STP_MODULE_NAME_LEN) < 0) { + errk("userspace copy failed\n"); + return; + } + dbug_unwind(1, "name=%s\n", name); + if (!strcmp(name,"*")) { + /* OK, all initial unwind data received. Ready to go. */ + _stp_ctl_send(STP_TRANSPORT, NULL, 0); + return; + } + count -= STP_MODULE_NAME_LEN; + buf += STP_MODULE_NAME_LEN; + + if (get_user(unwind_len, (u64 __user *)buf)) { + errk("userspace copy failed\n"); + return; + } + count -= sizeof(u64); + buf += sizeof(u64); + if (count != unwind_len) { + dbug_unwind(1, "count=%d unwind_len=%d\n", (int)count, (int)unwind_len); + return; + } + + STP_RLOCK_MODULES; + for (i = 0; i < _stp_num_modules; i++) { + if (strcmp(name, _stp_modules[i]->name) == 0) + break; + } + if (unlikely(i == _stp_num_modules)) { + dbug_unwind(1, "module %s not found!\n", name); + STP_RUNLOCK_MODULES; + return; + } + m = _stp_modules[i]; + write_lock(&m->lock); + STP_RUNLOCK_MODULES; + + /* allocate space for unwind data */ + m->unwind_data = _stp_kmalloc(count); + if (unlikely(m->unwind_data == NULL)) { + m->unwind_data = _stp_vmalloc(count); + if (m->unwind_data == NULL) { + errk("kmalloc failed\n"); + goto done; } - rwlock_init(&_stp_modules[0]->lock); - _stp_symbol_state = 1; - break; - case 1: - dbug(DEBUG_SYMBOLS, "got stap_symbols, count=%d\n", count); - if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count)) - return -EFAULT; - _stp_symbol_state = 2; - break; - case 2: - dbug(DEBUG_SYMBOLS, "got symbol data, count=%d buf=%p\n", count, buf); - if (copy_from_user (_stp_modules[0]->symbol_data, buf, count)) - return -EFAULT; - _stp_num_modules = 1; - - s = _stp_modules[0]->symbols; - for (i = 0; i < _stp_modules[0]->num_symbols; i++) - s[i].symbol += (long)_stp_modules[0]->symbol_data; - - _stp_symbol_state = 3; - /* NB: this mapping is used by kernel/_stext pseudo-relocations. */ - _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); - _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); - _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text; - _stp_modules_by_addr[0] = _stp_modules[0]; - dbug(DEBUG_SYMBOLS, "Got kernel symbols. text=%p len=%u\n", - (int64_t)_stp_modules[0]->text, _stp_modules[0]->text_size); - break; - case 3: - dbug(DEBUG_UNWIND, "got unwind data, count=%d\n", count); - _stp_symbol_state = 4; - if (copy_from_user (_stp_modules[0]->unwind_data, buf, count)) { - _dbug("cfu failed\n"); - return -EFAULT; + m->allocated.unwind_data = 1; + } + + if (unlikely(copy_from_user(m->unwind_data, buf, count))) { + errk("userspace copy failed\n"); + if (m->unwind_data) { + if (m->allocated.unwind_data) + _stp_vfree(m->unwind_data); + else + _stp_kfree(m->unwind_data); + m->unwind_data = NULL; } - _stp_modules[0]->unwind_data_len = count; - break; - default: - errk("unexpected symbol data of size %d.\n", count); + goto done; } - return count; + m->unwind_data_len = count; + _stp_create_unwind_hdr(m); +done: + write_unlock(&m->lock); } static int _stp_compare_addr(const void *p1, const void *p2) { struct _stp_symbol *s1 = (struct _stp_symbol *)p1; struct _stp_symbol *s2 = (struct _stp_symbol *)p2; - if (s1->addr == s2->addr) return 0; - if (s1->addr < s2->addr) return -1; + if (s1->addr == s2->addr) + return 0; + if (s1->addr < s2->addr) + return -1; return 1; } @@ -332,18 +339,17 @@ static void generic_swap(void *a, void *b, int size) * it less suitable for kernel use. */ void _stp_sort(void *base, size_t num, size_t size, - int (*cmp)(const void *, const void *), - void (*swap)(void *, void *, int size)) + int (*cmp) (const void *, const void *), void (*swap) (void *, void *, int size)) { /* pre-scale counters for performance */ - int i = (num/2 - 1) * size, n = num * size, c, r; + int i = (num / 2 - 1) * size, n = num * size, c, r; if (!swap) swap = (size == 4 ? u32_swap : generic_swap); /* heapify */ - for ( ; i >= 0; i -= size) { - for (r = i; r * 2 + size < n; r = c) { + for (; i >= 0; i -= size) { + for (r = i; r * 2 + size < n; r = c) { c = r * 2 + size; if (c < n - size && cmp(base + c, base + c + size) < 0) c += size; @@ -367,65 +373,114 @@ void _stp_sort(void *base, size_t num, size_t size, } } +/* filter out section names we don't care about */ +static int _stp_section_is_interesting(const char *name) +{ + int ret = 1; + if (!strncmp("__", name, 2) + || !strncmp(".note", name, 5) + || !strncmp(".gnu", name, 4) + || !strncmp(".mod", name, 4)) + ret = 0; + return ret; +} + /* Create a new _stp_module and load the symbols */ -static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod, uint32_t unwind_len) +static struct _stp_module *_stp_load_module_symbols(struct module *mod) { - unsigned i, num=0; - struct module *m = (struct module *)imod->module; - struct _stp_module *mod = NULL; - char *dataptr; + int i, num, overflow = 0; + struct module_sect_attrs *sa; + unsigned sect_size = 0, sect_num = 0, sym_size, sym_num; + struct _stp_module *sm; + char *dataptr, *endptr; + + sa = mod->sect_attrs; + /* calculate how much space to allocate for section strings */ + for (i = 0; i < sa->nsections; i++) { + if (_stp_section_is_interesting(sa->attrs[i].name)) { + sect_num++; + sect_size += strlen(sa->attrs[i].name) + 1; + dbug_sym(2, "\t%s\t%lx\n", sa->attrs[i].name, sa->attrs[i].address); + } + } + sect_size += sect_num * sizeof(struct _stp_symbol); + + /* and how much space for symbols */ + sym_num = _stp_get_sym_sizes(mod, &sym_size); - if (m == NULL) { - kbug(DEBUG_SYMBOLS, "imod->module is NULL\n"); + sm = _stp_alloc_module(sect_size, sym_num, sym_size); + if (!sm) { + errk("failed to allocate memory for module.\n"); return NULL; } - if (try_module_get(m)) { - mod = _stp_alloc_module_from_module(m, unwind_len); - if (mod == NULL) { - module_put(m); - errk("failed to allocate memory for module.\n"); - return NULL; - } + strlcpy(sm->name, mod->name, STP_MODULE_NAME_LEN); + sm->module = (unsigned long)mod; + sm->text = (unsigned long)mod->module_core; + sm->text_size = mod->core_text_size; + sm->data = 0; /* fixme */ + sm->num_sections = sect_num; + rwlock_init(&sm->lock); - strlcpy(mod->name, imod->name, STP_MODULE_NAME_LEN); - mod->module = imod->module; - mod->text = imod->text; - mod->data = imod->data; - mod->num_sections = imod->num_sections; - mod->sections = imod->sections; - mod->text_size = m->core_text_size; - rwlock_init(&mod->lock); - - /* now copy all the symbols we are interested in */ - dataptr = mod->symbol_data; - for (i=0; i < m->num_symtab; i++) { - char *str = (char *)(m->strtab + m->symtab[i].st_name); - if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) { - mod->symbols[num].symbol = dataptr; - mod->symbols[num].addr = m->symtab[i].st_value; - while (*str) *dataptr++ = *str++; - *dataptr++ = 0; - num++; + /* copy in section data */ + dataptr = (char *)((long)sm->sections + sect_num * sizeof(struct _stp_symbol)); + endptr = (char *)((long)sm->sections + sect_size); + num = 0; + for (i = 0; i < sa->nsections; i++) { + size_t len, maxlen; + if (_stp_section_is_interesting(sa->attrs[i].name)) { + sm->sections[num].addr = sa->attrs[i].address; + sm->sections[num].symbol = dataptr; + maxlen = (size_t) (endptr - dataptr); + len = strlcpy(dataptr, sa->attrs[i].name, maxlen); + if (unlikely(len >= maxlen)) { + _dbug("dataptr=%lx endptr=%lx len=%d maxlen=%d\n", dataptr, endptr, len, maxlen); + overflow = 1; } + dataptr += len + 1; + num++; } - module_put(m); + } + if (unlikely(overflow)) { + errk("Section names truncated!!! Should never happen!!\n"); + *endptr = 0; + overflow = 0; + } - /* sort symbols by address */ - _stp_sort (mod->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol); + /* now copy all the symbols we are interested in */ + dataptr = sm->symbol_data; + endptr = dataptr + sym_size - 1; + num = 0; + for (i = 0; i < mod->num_symtab; i++) { + char *str = (char *)(mod->strtab + mod->symtab[i].st_name); + if (*str != '\0' && _stp_sym_type_ok(mod->symtab[i].st_info)) { + sm->symbols[num].symbol = dataptr; + sm->symbols[num].addr = mod->symtab[i].st_value; + while (*str && (dataptr < endptr)) + *dataptr++ = *str++; + if (unlikely(*str)) + overflow = 1; + *dataptr++ = 0; + num++; + } } - return mod; + if (unlikely(overflow)) + errk("Symbol names truncated!!! Should never happen!!\n"); + + /* sort symbols by address */ + _stp_sort(sm->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol); + + return sm; } -/* Remove any old module info from our database */ -static void _stp_module_exists_delete (struct _stp_module *mod) +/* Remove any old module info from our database. */ +static void _stp_module_exists_delete(struct _stp_module *mod) { int i, num; - /* remove any old modules with the same name */ for (num = 1; num < _stp_num_modules; num++) { if (strcmp(_stp_modules[num]->name, mod->name) == 0) { - dbug(DEBUG_SYMBOLS, "found existing module with name %s. Deleting.\n", mod->name); + dbug_sym(1, "found existing module with name %s. Deleting.\n", mod->name); _stp_del_module(_stp_modules[num]); break; } @@ -435,143 +490,61 @@ static void _stp_module_exists_delete (struct _stp_module *mod) for (num = 1; num < _stp_num_modules; num++) { if (mod->text + mod->text_size < _stp_modules_by_addr[num]->text) continue; - if (mod->text < _stp_modules_by_addr[num]->text - + _stp_modules_by_addr[num]->text_size) { - dbug(DEBUG_SYMBOLS, "New module %s overlaps with old module %s. Deleting old.\n", - mod->name, _stp_modules_by_addr[num]->name); + if (mod->text < _stp_modules_by_addr[num]->text + _stp_modules_by_addr[num]->text_size) { + dbug_sym(1, "New module %s overlaps with old module %s. Deleting old.\n", + mod->name, _stp_modules_by_addr[num]->name); _stp_del_module(_stp_modules_by_addr[num]); } } } -static int _stp_ins_module(struct _stp_module *mod) +static void _stp_ins_module(struct module *mod) { - int i, num, res, ret = 0; + int i, num, res; unsigned long flags; - - // kbug(DEBUG_SYMBOLS, "insert %s\n", mod->name); + struct _stp_module *m; + dbug_sym(1, "insert %s\n", mod->name); + m = _stp_load_module_symbols(mod); + if (m == NULL) + return; STP_WLOCK_MODULES; - - _stp_module_exists_delete(mod); - + _stp_module_exists_delete(m); /* check for overflow */ if (_stp_num_modules == STP_MAX_MODULES) { errk("Exceeded the limit of %d modules\n", STP_MAX_MODULES); - ret = -ENOMEM; goto done; } - + /* insert alphabetically in _stp_modules[] */ for (num = 1; num < _stp_num_modules; num++) - if (strcmp(_stp_modules[num]->name, mod->name) > 0) + if (strcmp(_stp_modules[num]->name, m->name) > 0) break; for (i = _stp_num_modules; i > num; i--) - _stp_modules[i] = _stp_modules[i-1]; - _stp_modules[num] = mod; - + _stp_modules[i] = _stp_modules[i - 1]; + _stp_modules[num] = m; /* insert by text address in _stp_modules_by_addr[] */ for (num = 1; num < _stp_num_modules; num++) - if (mod->text < _stp_modules_by_addr[num]->text) + if (m->text < _stp_modules_by_addr[num]->text) break; for (i = _stp_num_modules; i > num; i--) - _stp_modules_by_addr[i] = _stp_modules_by_addr[i-1]; - _stp_modules_by_addr[num] = mod; - + _stp_modules_by_addr[i] = _stp_modules_by_addr[i - 1]; + _stp_modules_by_addr[num] = m; _stp_num_modules++; - done: STP_WUNLOCK_MODULES; - return ret; + return; } - -/* Called from procfs.c when a STP_MODULE msg is received */ -static int _stp_do_module(const char __user *buf, int count) -{ - struct _stp_msg_module tmpmod; - struct _stp_module mod, *m; - unsigned i, section_len; - - if (count < (int)sizeof(tmpmod)) { - errk("expected %d and got %d\n", (int)sizeof(tmpmod), count); - return -EFAULT; - } - if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod))) - return -EFAULT; - - section_len = count - sizeof(tmpmod) - tmpmod.unwind_len; - if (section_len <= 0) { - errk("section_len = %d\n", section_len); - return -EFAULT; - } - dbug(DEBUG_SYMBOLS, "Got module %s, count=%d section_len=%d unwind_len=%d\n", - tmpmod.name, count, section_len, tmpmod.unwind_len); - - strcpy(mod.name, tmpmod.name); - mod.module = tmpmod.module; - mod.text = tmpmod.text; - mod.data = tmpmod.data; - mod.num_sections = tmpmod.num_sections; - - /* copy in section data */ - mod.sections = _stp_kmalloc(section_len); - if (mod.sections == NULL) { - errk("unable to allocate memory.\n"); - return -EFAULT; - } - if (copy_from_user ((char *)mod.sections, buf+sizeof(tmpmod), section_len)) { - _stp_kfree(mod.sections); - return -EFAULT; - } - for (i = 0; i < mod.num_sections; i++) { - mod.sections[i].symbol = - (char *)((long)mod.sections[i].symbol - + (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol))); - } - - #if 0 - for (i = 0; i < mod.num_sections; i++) - _dbug("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr); - #endif - - /* load symbols from tmpmod.module to mod */ - m = _stp_load_module_symbols(&mod, tmpmod.unwind_len); - if (m == NULL) { - _stp_kfree(mod.sections); - return 0; - } - - dbug(DEBUG_SYMBOLS, "module %s loaded. Text=%p text_size=%u\n", m->name, (int64_t)m->text, m->text_size); - /* finally copy unwind info */ - if (copy_from_user (m->unwind_data, buf+sizeof(tmpmod)+section_len, tmpmod.unwind_len)) { - _stp_free_module(m); - _stp_kfree(mod.sections); - return -EFAULT; - } - m->unwind_data_len = tmpmod.unwind_len; - - if (_stp_ins_module(m) < 0) { - _stp_free_module(m); - return -ENOMEM; - } - - return count; -} - -static int _stp_ctl_send (int type, void *data, int len); - -static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data) +static int _stp_module_load_notify(struct notifier_block *self, unsigned long val, void *data) { struct module *mod = (struct module *)data; struct _stp_module rmod; - switch (val) { case MODULE_STATE_COMING: - dbug(DEBUG_SYMBOLS, "module %s load notify\n", mod->name); - strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN); - _stp_ctl_send(STP_MODULE, &rmod, sizeof(struct _stp_module)); + dbug_sym(1, "module %s load notify\n", mod->name); + _stp_ins_module(mod); break; default: errk("module loaded? val=%ld\n", val); @@ -583,4 +556,63 @@ static struct notifier_block _stp_module_load_nb = { .notifier_call = _stp_module_load_notify, }; -#endif /* _SYMBOLS_C_ */ +#include +extern unsigned long _stp_modules_op; /* from stap */ +static int _stp_init_modules(void) +{ + loff_t pos = 0; + void *res; + struct module *mod; + + const struct seq_operations *modules_op = (const struct seq_operations *)_stp_modules_op; + /* Use the seq_file interface to safely get a list of installed modules */ + res = modules_op->start(NULL, &pos); + while (res) { + mod = list_entry(res, struct module, list); + _stp_ins_module(mod); + res = modules_op->next(NULL, res, &pos); + } + + if (register_module_notifier(&_stp_module_load_nb)) + errk("failed to load module notifier\n"); + + /* unlocks the list */ + modules_op->stop(NULL, NULL); + +#ifndef CONFIG_FRAME_POINTER + /* now that we have all the modules, ask for their unwind info */ + { + unsigned long flags; + int i, left = STP_CTL_BUFFER_SIZE; + char buf[STP_CTL_BUFFER_SIZE]; + char *ptr = buf; + *ptr = 0; + + STP_RLOCK_MODULES; + /* Loop through modules, sending module names packed into */ + /* messages of size STP_CTL_BUFFER. */ + for (i = 0; i < _stp_num_modules; i++) { + char *name = _stp_modules[i]->name; + int len = strlen(name); + if (len >= left) { + _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left); + ptr = buf; + left = STP_CTL_BUFFER_SIZE; + } + strlcpy(ptr, name, left); + ptr += len + 1; + left -= len + 1; + } + STP_RUNLOCK_MODULES; + + /* Send terminator. When we get this back from stapio */ + /* that means all the unwind info has been sent. */ + strlcpy(ptr, "*", left); + left -= 2; + _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left); + } +#endif + return 0; +} + +#endif /* _STP_SYMBOLS_C_ */ diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 8335e44b..aa96a50e 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -23,83 +23,47 @@ #include "../procfs.c" static struct utt_trace *_stp_utt = NULL; - +static unsigned int utt_seq = 1; +static int _stp_probes_started = 0; +pid_t _stp_target = 0; +static int _stp_exit_called = 0; +int _stp_exit_flag = 0; #ifdef STP_OLD_TRANSPORT #include "relayfs.c" +#include "procfs.c" #else #include "utt.c" +#include "control.c" #endif -static unsigned int utt_seq = 1; - -static int _stp_probes_started = 0; - /* module parameters */ static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); -pid_t _stp_target = 0; -static int _stp_exit_called = 0; -int _stp_exit_flag = 0; - /* forward declarations */ void probe_exit(void); int probe_start(void); void _stp_exit(void); -void _stp_handle_start (struct _stp_msg_start *st); -static void _stp_detach(void); -static void _stp_attach(void); /* check for new workqueue API */ -#ifdef DECLARE_DELAYED_WORK -static void _stp_work_queue (struct work_struct *data); +#ifdef DECLARE_DELAYED_WORK +static void _stp_work_queue(struct work_struct *data); static DECLARE_DELAYED_WORK(_stp_work, _stp_work_queue); #else -static void _stp_work_queue (void *data); +static void _stp_work_queue(void *data); static DECLARE_WORK(_stp_work, _stp_work_queue, NULL); #endif static struct workqueue_struct *_stp_wq; -static void _stp_ask_for_symbols(void); - -#ifdef STP_OLD_TRANSPORT -#include "procfs.c" -#else -#include "control.c" -#endif - -static void _stp_ask_for_symbols(void) -{ - struct _stp_msg_symbol req; - struct _stp_module mod; - static int sent_symbols = 0; - - if (sent_symbols == 0) { - /* ask for symbols and modules */ - kbug(DEBUG_SYMBOLS|DEBUG_TRANSPORT, "AFS\n"); - - req.endian = 0x1234; - req.ptr_size = sizeof(char *); - _stp_ctl_send(STP_SYMBOLS, &req, sizeof(req)); - - strcpy(mod.name, ""); - _stp_ctl_send(STP_MODULE, &mod, sizeof(mod)); - sent_symbols = 1; - } -} /* * _stp_handle_start - handle STP_START */ -void _stp_handle_start (struct _stp_msg_start *st) +void _stp_handle_start(struct _stp_msg_start *st) { - kbug (DEBUG_TRANSPORT, "stp_handle_start\n"); - - if (register_module_notifier(&_stp_module_load_nb)) - errk("failed to load module notifier\n"); - + dbug_trans(1, "stp_handle_start\n"); _stp_target = st->target; st->res = probe_start(); if (st->res >= 0) @@ -108,16 +72,15 @@ void _stp_handle_start (struct _stp_msg_start *st) _stp_ctl_send(STP_START, st, sizeof(*st)); } - /* common cleanup code. */ /* This is called from the kernel thread when an exit was requested */ /* by staprun or the exit() function. It is also called by transport_close() */ /* when the module is removed. In that case "dont_rmmod" is set to 1. */ /* We need to call it both times because we want to clean up properly */ /* when someone does /sbin/rmmod on a loaded systemtap module. */ -static void _stp_cleanup_and_exit (int dont_rmmod) +static void _stp_cleanup_and_exit(int dont_rmmod) { - kbug(DEBUG_TRANSPORT, "cleanup_and_exit (%d)\n", dont_rmmod); + dbug_trans(1, "cleanup_and_exit (%d)\n", dont_rmmod); if (!_stp_exit_called) { int failures; @@ -128,23 +91,24 @@ static void _stp_cleanup_and_exit (int dont_rmmod) _stp_exit_called = 1; if (_stp_probes_started) { - kbug(DEBUG_TRANSPORT, "calling probe_exit\n"); + dbug_trans(1, "calling probe_exit\n"); /* tell the stap-generated code to unload its probes, etc */ probe_exit(); - kbug(DEBUG_TRANSPORT, "done with probe_exit\n"); + dbug_trans(1, "done with probe_exit\n"); } failures = atomic_read(&_stp_transport_failures); if (failures) - _stp_warn ("There were %d transport failures.\n", failures); + _stp_warn("There were %d transport failures.\n", failures); - kbug(DEBUG_TRANSPORT, "************** calling startstop 0 *************\n"); - if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq); + dbug_trans(1, "************** calling startstop 0 *************\n"); + if (_stp_utt) + utt_trace_startstop(_stp_utt, 0, &utt_seq); - kbug(DEBUG_TRANSPORT, "ctl_send STP_EXIT\n"); + dbug_trans(1, "ctl_send STP_EXIT\n"); /* tell staprun to exit (if it is still there) */ _stp_ctl_send(STP_EXIT, &dont_rmmod, sizeof(int)); - kbug(DEBUG_TRANSPORT, "done with ctl_send STP_EXIT\n"); + dbug_trans(1, "done with ctl_send STP_EXIT\n"); } } @@ -153,7 +117,7 @@ static void _stp_cleanup_and_exit (int dont_rmmod) */ static void _stp_detach(void) { - kbug(DEBUG_TRANSPORT, "detach\n"); + dbug_trans(1, "detach\n"); _stp_attached = 0; _stp_pid = 0; @@ -169,10 +133,10 @@ static void _stp_detach(void) */ static void _stp_attach(void) { - kbug(DEBUG_TRANSPORT, "attach\n"); + dbug_trans(1, "attach\n"); _stp_attached = 1; _stp_pid = current->pid; - utt_set_overwrite(0); + utt_set_overwrite(0); queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } @@ -180,10 +144,10 @@ static void _stp_attach(void) * _stp_work_queue - periodically check for IO or exit * This is run by a kernel thread and may sleep. */ -#ifdef DECLARE_DELAYED_WORK -static void _stp_work_queue (struct work_struct *data) +#ifdef DECLARE_DELAYED_WORK +static void _stp_work_queue(struct work_struct *data) #else -static void _stp_work_queue (void *data) +static void _stp_work_queue(void *data) #endif { int do_io = 0; @@ -211,19 +175,19 @@ static void _stp_work_queue (void *data) */ void _stp_transport_close() { - kbug(DEBUG_TRANSPORT, "%d: ************** transport_close *************\n", current->pid); + dbug_trans(1, "%d: ************** transport_close *************\n", current->pid); _stp_cleanup_and_exit(1); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); - if (_stp_utt) utt_trace_remove(_stp_utt); + if (_stp_utt) + utt_trace_remove(_stp_utt); _stp_free_modules(); _stp_kill_time(); - _stp_print_cleanup(); /* free print buffers */ + _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); - kbug(DEBUG_TRANSPORT, "---- CLOSED ----\n"); + dbug_trans(1, "---- CLOSED ----\n"); } - static struct utt_trace *_stp_utt_open(void) { struct utt_trace_setup utts; @@ -249,22 +213,22 @@ int _stp_transport_init(void) { int ret; - kbug(DEBUG_TRANSPORT, "transport_init\n"); + dbug_trans(1, "transport_init\n"); _stp_init_pid = current->pid; _stp_uid = current->uid; _stp_gid = current->gid; #ifdef RELAY_GUEST - /* Guest scripts use relay only for reporting warnings and errors */ - _stp_subbuf_size = 65536; - _stp_nsubbufs = 2; + /* Guest scripts use relay only for reporting warnings and errors */ + _stp_subbuf_size = 65536; + _stp_nsubbufs = 2; #endif if (_stp_bufsize) { unsigned size = _stp_bufsize * 1024 * 1024; _stp_subbuf_size = ((size >> 2) + 1) * 65536; _stp_nsubbufs = size / _stp_subbuf_size; - kbug(DEBUG_TRANSPORT, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); + dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } /* initialize timer code */ @@ -286,41 +250,57 @@ int _stp_transport_init(void) if (_stp_print_init() < 0) goto err2; + /* start transport */ utt_trace_startstop(_stp_utt, 1, &utt_seq); /* create workqueue of kernel threads */ _stp_wq = create_workqueue("systemtap"); if (!_stp_wq) goto err3; + + _stp_transport_state = 1; + + dbug_trans(1, "calling init_kernel_symbols\n"); + if (_stp_init_kernel_symbols() < 0) + goto err4; + + dbug_trans(1, "calling init_modules\n"); + if (_stp_init_modules() < 0) + goto err4; + return 0; +err4: + errk("failed to initialize modules\n"); + _stp_free_modules(); + destroy_workqueue(_stp_wq); err3: _stp_print_cleanup(); err2: _stp_unregister_ctl_channel(); err1: - if (_stp_utt) utt_trace_remove(_stp_utt); + if (_stp_utt) + utt_trace_remove(_stp_utt); err0: _stp_kill_time(); return -1; } - static inline void _stp_lock_inode(struct inode *inode) { #ifdef DEFINE_MUTEX - mutex_lock(&inode->i_mutex); + mutex_lock(&inode->i_mutex); #else - down(&inode->i_sem); + down(&inode->i_sem); #endif } static inline void _stp_unlock_inode(struct inode *inode) { #ifdef DEFINE_MUTEX - mutex_unlock(&inode->i_mutex); + mutex_unlock(&inode->i_mutex); #else - up(&inode->i_sem); + up(&inode->i_sem); #endif } @@ -358,7 +338,8 @@ static void _stp_unlock_debugfs(void) /* utt.c and relayfs.c. Will not be necessary if utt is included */ /* in the kernel. */ -static struct dentry *_stp_get_root_dir(const char *name) { +static struct dentry *_stp_get_root_dir(const char *name) +{ struct file_system_type *fs; struct dentry *root; struct super_block *sb; @@ -377,7 +358,6 @@ static struct dentry *_stp_get_root_dir(const char *name) { errk("Couldn't lock transport directory.\n"); return NULL; } - #ifdef STP_OLD_TRANSPORT root = relayfs_create_dir(name, NULL); #else @@ -389,12 +369,12 @@ static struct dentry *_stp_get_root_dir(const char *name) { _stp_lock_inode(sb->s_root->d_inode); root = lookup_one_len(name, sb->s_root, strlen(name)); _stp_unlock_inode(sb->s_root->d_inode); - kbug(DEBUG_TRANSPORT, "root=%p\n", root); + errk("ERROR: root=%p\n", root); if (!IS_ERR(root)) dput(root); else { root = NULL; - kbug(DEBUG_TRANSPORT, "Could not create or find transport directory.\n"); + errk("Could not create or find transport directory.\n"); } } _stp_unlock_debugfs(); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 6dc00d2b..dc499961 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -7,21 +7,37 @@ #include "transport_msgs.h" -void _stp_warn (const char *fmt, ...); - +/* The size of print buffers. This limits the maximum */ +/* amount of data a print can send. */ #define STP_BUFFER_SIZE 8192 +/* STP_CTL_BUFFER_SIZE is the maximum size of a message */ +/* exchanged on the control channel. */ +#ifdef STP_OLD_TRANSPORT +/* Old transport sends print output on control channel */ +#define STP_CTL_BUFFER_SIZE STP_BUFFER_SIZE +#else +#define STP_CTL_BUFFER_SIZE 256 +#endif + /* how often the work queue wakes up and checks buffers */ #define STP_WORK_TIMER (HZ/100) static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; + +void _stp_warn (const char *fmt, ...); extern void _stp_transport_close(void); extern int _stp_print_init(void); extern void _stp_print_cleanup(void); static struct dentry *_stp_get_root_dir(const char *name); static int _stp_lock_debugfs(void); static void _stp_unlock_debugfs(void); +static int _stp_ctl_send(int type, void *data, int len); +static void _stp_attach(void); +static void _stp_detach(void); +void _stp_handle_start(struct _stp_msg_start *st); + int _stp_pid = 0; uid_t _stp_uid = 0; gid_t _stp_gid = 0; diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 55de2d4a..0e65b63a 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -23,8 +23,7 @@ enum STP_EXIT, STP_OOB_DATA, STP_SYSTEM, - STP_SYMBOLS, - STP_MODULE, + STP_UNWIND, STP_TRANSPORT, STP_CONNECT, STP_DISCONNECT, @@ -36,18 +35,16 @@ enum STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, #endif - STP_MAX_CMD }; -#ifdef DEBUG_TRANSPORT +#ifdef DEBUG_TRANS static const char *_stp_command_name[] = { "STP_START", "STP_EXIT", "STP_OOB_DATA", "STP_SYSTEM", - "STP_SYMBOLS", - "STP_MODULE", + "STP_UNWIND", "STP_TRANSPORT", "STP_CONNECT", "STP_DISCONNECT", @@ -59,68 +56,34 @@ static const char *_stp_command_name[] = { "STP_REALTIME_DATA", #endif }; -#endif /* DEBUG_TRANSPORT */ +#endif /* DEBUG_TRANS */ /* control channel messages */ -/* command to execute: sent to staprun */ +/* command to execute: module->stapio */ struct _stp_msg_cmd { char cmd[128]; }; -/* request for symbol data. sent to staprun */ -struct _stp_msg_symbol +/* Unwind data. stapio->module */ +struct _stp_msg_unwind { - int32_t endian; - int32_t ptr_size; + /* the module name, or "*" for all */ + char name[STP_MODULE_NAME_LEN]; + /* length of unwind data */ + uint64_t unwind_len; + /* data ...*/ }; /* Request to start probes. */ -/* Sent from staprun. Then returned from module. */ +/* stapio->module->stapio */ struct _stp_msg_start { pid_t target; int32_t res; // for reply: result of probe_start() }; -struct _stp_symbol32 -{ - uint32_t addr; - uint32_t symbol; -}; - -struct _stp_symbol64 -{ - uint64_t addr; - uint64_t symbol; -}; - -struct _stp_msg_symbol_hdr -{ - uint32_t num_syms; - uint32_t sym_size; - uint32_t unwind_size; -}; - -struct _stp_msg_module { - /* the module name, or "" for kernel */ - char name[STP_MODULE_NAME_LEN]; - - /* A pointer to the struct module */ - uint64_t module; - - /* the start of the module's text and data sections */ - uint64_t text; - uint64_t data; - - /* how many sections this module has */ - uint32_t num_sections; - - /* length of unwind data */ - uint32_t unwind_len; -}; - #ifdef STP_OLD_TRANSPORT /**** for compatibility with old relayfs ****/ struct _stp_buf_info diff --git a/runtime/unwind.c b/runtime/unwind.c new file mode 100644 index 00000000..9a5d61e8 --- /dev/null +++ b/runtime/unwind.c @@ -0,0 +1,895 @@ +/* + * Copyright (C) 2002-2006 Novell, Inc. + * Jan Beulich + * This code is released under version 2 of the GNU GPL. + * + * A simple API for unwinding kernel stacks. This is used for + * debugging and error reporting purposes. The kernel doesn't need + * full-blown stack unwinding with all the bells and whistles, so there + * is not much point in implementing the full Dwarf2 unwind API. + */ + +#include "unwind/unwind.h" + +struct eh_frame_hdr_table_entry { + unsigned long start, fde; +}; + +static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2) +{ + const struct eh_frame_hdr_table_entry *e1 = p1; + const struct eh_frame_hdr_table_entry *e2 = p2; + return (e1->start > e2->start) - (e1->start < e2->start); +} + +static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) +{ + struct eh_frame_hdr_table_entry *e1 = p1; + struct eh_frame_hdr_table_entry *e2 = p2; + unsigned long v; + + v = e1->start; + e1->start = e2->start; + e2->start = v; + v = e1->fde; + e1->fde = e2->fde; + e2->fde = v; +} + +/* Build a binary-searchable unwind header. Also do some + * validity checks. In the future we might use */ +/* .eh_frame_hdr if it is already present. */ +static void _stp_create_unwind_hdr(struct _stp_module *m) +{ + const u8 *ptr; + unsigned long tableSize, hdrSize, last; + unsigned n = 0; + const u32 *fde; + int bad_order = 0; + struct { + u8 version; + u8 eh_frame_ptr_enc; + u8 fde_count_enc; + u8 table_enc; + unsigned long eh_frame_ptr; + unsigned int fde_count; + struct eh_frame_hdr_table_entry table[]; + } __attribute__ ((__packed__)) * header = NULL; + + /* already did this or no data? */ + if (m->unwind_hdr || m->unwind_data_len == 0) + return; + + tableSize = m->unwind_data_len; + if (tableSize & (sizeof(*fde) - 1)) { + dbug_unwind(1, "tableSize=0x%x not a multiple of 0x%x\n", (int)tableSize, (int)sizeof(*fde)); + goto bad; + } + + /* count the FDEs */ + for (fde = m->unwind_data; + tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; + tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + signed ptrType; + const u32 *cie; + + /* check for extended length */ + if ((*fde & 0xfffffff0) == 0xfffffff0) { + dbug_unwind(1, "Module %s has extended-length CIE or FDE."); + dbug_unwind(1, "This is not supported at this time."); + goto bad; + } + cie = cie_for_fde(fde, m); + if (cie == ¬_fde) + continue; /* fde was a CIE. That's OK, just skip it. */ + if (cie == NULL || cie == &bad_cie || (ptrType = fde_pointer_type(cie)) < 0) + goto bad; + /* we have a real FDE */ + ptr = (const u8 *)(fde + 2); + if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType)) + goto bad; + ++n; + } + + if (tableSize || !n) { + dbug_unwind(1, "%s: tableSize=%ld, n=%d\n", m->name, tableSize, n); + goto bad; + } + + hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) + 2 * n * sizeof(unsigned long); + header = _stp_kmalloc(hdrSize); + if (header == NULL) { + header = _stp_vmalloc(hdrSize); + if (header == NULL) + return; + m->allocated.unwind_hdr = 1; + } + + header->version = 1; + header->eh_frame_ptr_enc = DW_EH_PE_absptr; + header->fde_count_enc = DW_EH_PE_data4; + header->table_enc = DW_EH_PE_absptr; + _stp_put_unaligned((unsigned long)m->unwind_data, &header->eh_frame_ptr); + + BUILD_BUG_ON(offsetof(typeof(*header), fde_count) + % __alignof(typeof(header->fde_count))); + header->fde_count = n; + + BUILD_BUG_ON(offsetof(typeof(*header), table) % __alignof(typeof(*header->table))); + + n = 0; + last = 0; + tableSize = m->unwind_data_len; + for (fde = m->unwind_data; tableSize; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + const u32 *cie = cie_for_fde(fde, m); + if (cie == ¬_fde) + continue; + if (cie == NULL || cie == &bad_cie) + goto bad; + /* we have a real FDE */ + ptr = (const u8 *)(fde + 2); + header->table[n].start = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, fde_pointer_type(cie)); + header->table[n].fde = (unsigned long)fde; + if (header->table[n].start < last) + bad_order++; + last = header->table[n].start; + ++n; + } + WARN_ON(n != header->fde_count); + + /* Is sort ever necessary? */ + if (bad_order) + _stp_sort(header->table, n, sizeof(*header->table), cmp_eh_frame_hdr_table_entries, + swap_eh_frame_hdr_table_entries); + + m->unwind_hdr_len = hdrSize; + m->unwind_hdr = header; + return; + + /* unwind data is not acceptable. free it and return */ +bad: + dbug_unwind(1, "unwind data for %s is unacceptable. Freeing.", m->name); + if (header) { + if (m->allocated.unwind_hdr) { + m->allocated.unwind_hdr = 0; + _stp_vfree(header); + } else + _stp_kfree(header); + } + if (m->unwind_data) { + if (m->allocated.unwind_data) + _stp_vfree(m->unwind_data); + else + _stp_kfree(m->unwind_data); + m->unwind_data = NULL; + m->unwind_data_len = 0; + } + return; +} + +static uleb128_t get_uleb128(const u8 **pcur, const u8 *end) +{ + const u8 *cur = *pcur; + uleb128_t value = 0; + unsigned shift; + + for (shift = 0; cur < end; shift += 7) { + if (shift + 7 > 8 * sizeof(value) + && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { + cur = end + 1; + break; + } + value |= (uleb128_t)(*cur & 0x7f) << shift; + if (!(*cur++ & 0x80)) + break; + } + *pcur = cur; + + return value; +} + +static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) +{ + const u8 *cur = *pcur; + sleb128_t value = 0; + unsigned shift; + + for (shift = 0; cur < end; shift += 7) { + if (shift + 7 > 8 * sizeof(value) + && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { + cur = end + 1; + break; + } + value |= (sleb128_t)(*cur & 0x7f) << shift; + if (!(*cur & 0x80)) { + value |= -(*cur++ & 0x40) << shift; + break; + } + } + *pcur = cur; + + return value; +} + +/* given an FDE, find its CIE */ +static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m) +{ + const u32 *cie; + + /* check that length is proper */ + if (!*fde || (*fde & (sizeof(*fde) - 1))) + return &bad_cie; + + /* CIE id for eh_frame is 0, otherwise 0xffffffff */ + if (m->unwind_is_ehframe && fde[1] == 0) + return ¬_fde; + else if (fde[1] == 0xffffffff) + return ¬_fde; + + /* OK, must be an FDE. Now find its CIE. */ + + /* CIE_pointer must be a proper offset */ + if ((fde[1] & (sizeof(*fde) - 1)) || fde[1] > (unsigned long)(fde + 1) - (unsigned long)m->unwind_data) { + dbug_unwind(1, "fde[1]=%lx fde+1=%lx, unwind_data=%lx %lx\n", + (unsigned long)fde[1], (unsigned long)(fde + 1), + (unsigned long)m->unwind_data, (unsigned long)(fde + 1) - (unsigned long)m->unwind_data); + return NULL; /* this is not a valid FDE */ + } + + /* cie pointer field is different in eh_frame vs debug_frame */ + if (m->unwind_is_ehframe) + cie = fde + 1 - fde[1] / sizeof(*fde); + else + cie = m->unwind_data + fde[1]; + + if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde) + || (*cie & (sizeof(*cie) - 1)) + || (cie[1] != 0xffffffff && cie[1] != 0)) { + dbug_unwind(1, "cie is not valid %lx %x %x %x\n", cie, *cie, fde[1], cie[1]); + return NULL; /* this is not a (valid) CIE */ + } + + return cie; +} + +/* read an encoded pointer */ +static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType) +{ + unsigned long value = 0; + union { + const u8 *p8; + const u16 *p16u; + const s16 *p16s; + const u32 *p32u; + const s32 *p32s; + const unsigned long *pul; + } ptr; + + if (ptrType < 0 || ptrType == DW_EH_PE_omit) + return 0; + + ptr.p8 = *pLoc; + switch (ptrType & DW_EH_PE_FORM) { + case DW_EH_PE_data2: + if (end < (const void *)(ptr.p16u + 1)) + return 0; + if (ptrType & DW_EH_PE_signed) + value = _stp_get_unaligned(ptr.p16s++); + else + value = _stp_get_unaligned(ptr.p16u++); + break; + case DW_EH_PE_data4: +#ifdef CONFIG_64BIT + if (end < (const void *)(ptr.p32u + 1)) + return 0; + if (ptrType & DW_EH_PE_signed) + value = _stp_get_unaligned(ptr.p32s++); + else + value = _stp_get_unaligned(ptr.p32u++); + break; + case DW_EH_PE_data8: + BUILD_BUG_ON(sizeof(u64) != sizeof(value)); +#else + BUILD_BUG_ON(sizeof(u32) != sizeof(value)); +#endif + case DW_EH_PE_absptr: + if (end < (const void *)(ptr.pul + 1)) + return 0; + value = _stp_get_unaligned(ptr.pul++); + break; + case DW_EH_PE_leb128: + BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value)); + value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end) + : get_uleb128(&ptr.p8, end); + if ((const void *)ptr.p8 > end) + return 0; + break; + default: + return 0; + } + switch (ptrType & DW_EH_PE_ADJUST) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + value += (unsigned long)*pLoc; + break; + default: + return 0; + } + if ((ptrType & DW_EH_PE_indirect) + && __stp_get_user(value, (unsigned long *)value)) + return 0; + *pLoc = ptr.p8; + + return value; +} + +static signed fde_pointer_type(const u32 *cie) +{ + const u8 *ptr = (const u8 *)(cie + 2); + unsigned version = *ptr; + + if (version != 1) + return -1; /* unsupported */ + if (*++ptr) { + const char *aug; + const u8 *end = (const u8 *)(cie + 1) + *cie; + uleb128_t len; + + /* check if augmentation size is first (and thus present) */ + if (*ptr != 'z') + return -1; + /* check if augmentation string is nul-terminated */ + if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) + return -1; + ++ptr; /* skip terminator */ + get_uleb128(&ptr, end); /* skip code alignment */ + get_sleb128(&ptr, end); /* skip data alignment */ + /* skip return address column */ + version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end); + len = get_uleb128(&ptr, end); /* augmentation length */ + if (ptr + len < ptr || ptr + len > end) + return -1; + end = ptr + len; + while (*++aug) { + if (ptr >= end) + return -1; + switch (*aug) { + case 'L': + ++ptr; + break; + case 'P':{ + signed ptrType = *ptr++; + + if (!read_pointer(&ptr, end, ptrType) || ptr > end) + return -1; + } + break; + case 'R': + return *ptr; + default: + return -1; + } + } + } + return DW_EH_PE_absptr; +} + +static int advance_loc(unsigned long delta, struct unwind_state *state) +{ + state->loc += delta * state->codeAlign; + dbug_unwind(1, "state->loc=%lx\n", state->loc); + return delta > 0; +} + +static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value, struct unwind_state *state) +{ + dbug_unwind(1, "reg=%d, where=%d, value=%lx\n", reg, where, value); + if (reg < ARRAY_SIZE(state->regs)) { + state->regs[reg].where = where; + state->regs[reg].value = value; + } +} + +static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, signed ptrType, struct unwind_state *state) +{ + union { + const u8 *p8; + const u16 *p16; + const u32 *p32; + } ptr; + int result = 1; + + if (start != state->cieStart) { + state->loc = state->org; + result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state); + if (targetLoc == 0 && state->label == NULL) + return result; + } + + for (ptr.p8 = start; result && ptr.p8 < end;) { + switch (*ptr.p8 >> 6) { + uleb128_t value; + case 0: + switch (*ptr.p8++) { + case DW_CFA_nop: + dbug_unwind(1, "DW_CFA_nop\n"); + break; + case DW_CFA_set_loc: + if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0) + result = 0; + dbug_unwind(1, "DW_CFA_set_loc %lx (result=%d)\n", state->loc, result); + break; + case DW_CFA_advance_loc1: + result = ptr.p8 < end && advance_loc(*ptr.p8++, state); + dbug_unwind(1, "DW_CFA_advance_loc1 %d\n", result); + break; + case DW_CFA_advance_loc2: + result = ptr.p8 <= end + 2 && advance_loc(*ptr.p16++, state); + dbug_unwind(1, "DW_CFA_advance_loc2 %d\n", result); + break; + case DW_CFA_advance_loc4: + result = ptr.p8 <= end + 4 && advance_loc(*ptr.p32++, state); + dbug_unwind(1, "DW_CFA_advance_loc4 %d\n", result); + break; + case DW_CFA_offset_extended: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_offset_extended\n"); + break; + case DW_CFA_val_offset: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Value, get_uleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_val_offset\n"); + break; + case DW_CFA_offset_extended_sf: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Memory, get_sleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_offset_extended_sf\n"); + break; + case DW_CFA_val_offset_sf: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Value, get_sleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_val_offset_sf\n"); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state); + dbug_unwind(1, "DW_CFA_undefined\n"); + break; + case DW_CFA_register: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Register, get_uleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_register\n"); + break; + case DW_CFA_remember_state: + dbug_unwind(1, "DW_CFA_remember_state\n"); + if (ptr.p8 == state->label) { + state->label = NULL; + return 1; + } + if (state->stackDepth >= MAX_STACK_DEPTH) + return 0; + state->stack[state->stackDepth++] = ptr.p8; + break; + case DW_CFA_restore_state: + dbug_unwind(1, "DW_CFA_restore_state\n"); + if (state->stackDepth) { + const uleb128_t loc = state->loc; + const u8 *label = state->label; + + state->label = state->stack[state->stackDepth - 1]; + memcpy(&state->cfa, &badCFA, sizeof(state->cfa)); + memset(state->regs, 0, sizeof(state->regs)); + state->stackDepth = 0; + result = processCFI(start, end, 0, ptrType, state); + state->loc = loc; + state->label = label; + } else + return 0; + break; + case DW_CFA_def_cfa: + state->cfa.reg = get_uleb128(&ptr.p8, end); + dbug_unwind(1, "DW_CFA_def_cfa reg=%ld\n", state->cfa.reg); + /*nobreak */ + case DW_CFA_def_cfa_offset: + state->cfa.offs = get_uleb128(&ptr.p8, end); + dbug_unwind(1, "DW_CFA_def_cfa_offset offs=%lx\n", state->cfa.offs); + break; + case DW_CFA_def_cfa_sf: + state->cfa.reg = get_uleb128(&ptr.p8, end); + dbug_unwind(1, "DW_CFA_def_cfa_sf reg=%ld\n", state->cfa.reg); + /*nobreak */ + case DW_CFA_def_cfa_offset_sf: + state->cfa.offs = get_sleb128(&ptr.p8, end) * state->dataAlign; + dbug_unwind(1, "DW_CFA_def_cfa_offset_sf offs=%lx\n", state->cfa.offs); + break; + case DW_CFA_def_cfa_register: + state->cfa.reg = get_uleb128(&ptr.p8, end); + dbug_unwind(1, "DW_CFA_def_cfa_register reg=%ld\n", state->cfa.reg); + break; + /*todo case DW_CFA_def_cfa_expression: */ + /*todo case DW_CFA_expression: */ + /*todo case DW_CFA_val_expression: */ + case DW_CFA_GNU_args_size: + get_uleb128(&ptr.p8, end); + dbug_unwind(1, "DW_CFA_GNU_args_size\n"); + break; + case DW_CFA_GNU_negative_offset_extended: + value = get_uleb128(&ptr.p8, end); + set_rule(value, Memory, (uleb128_t)0 - get_uleb128(&ptr.p8, end), state); + dbug_unwind(1, "DW_CFA_GNU_negative_offset_extended\n"); + break; + case DW_CFA_GNU_window_save: + default: + dbug_unwind(1, "unimplemented call frame instruction: 0x%x\n", *(ptr.p8 - 1)); + result = 0; + break; + } + break; + case 1: + result = advance_loc(*ptr.p8++ & 0x3f, state); + dbug_unwind(1, "case 1\n"); + break; + case 2: + value = *ptr.p8++ & 0x3f; + set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); + dbug_unwind(1, "case 2\n"); + break; + case 3: + set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); + dbug_unwind(1, "case 3\n"); + break; + } + if (ptr.p8 > end) + result = 0; + if (result && targetLoc != 0 && targetLoc < state->loc) + return 1; + } + return result && ptr.p8 == end && (targetLoc == 0 || state->label == NULL); +} + +/* If we previously created an unwind header, then use it now to binary search */ +/* for the FDE corresponding to pc. */ + +static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m) +{ + const u8 *ptr, *end, *hdr = m->unwind_hdr; + unsigned long startLoc; + u32 *fde = NULL; + unsigned num, tableSize, t2; + + /* TOTO: only really need to test hdr == NULL */ + /* The rest should be validated at load time */ + + if (hdr == NULL || hdr[0] != 1) + return NULL; + + dbug_unwind(1, "search for %lx", pc); + + /* table_enc */ + switch (hdr[3] & DW_EH_PE_FORM) { + case DW_EH_PE_absptr: + tableSize = sizeof(unsigned long); + break; + case DW_EH_PE_data2: + tableSize = 2; + break; + case DW_EH_PE_data4: + tableSize = 4; + break; + case DW_EH_PE_data8: + tableSize = 8; + break; + default: + dbug_unwind(1, "bad table encoding"); + return NULL; + } + ptr = hdr + 4; + end = hdr + m->unwind_hdr_len; + + if (read_pointer(&ptr, end, hdr[1]) != (unsigned long)m->unwind_data) { + dbug_unwind(1, "eh_frame_ptr not valid"); + return NULL; + } + + num = read_pointer(&ptr, end, hdr[2]); + if (num == 0 || num != (end - ptr) / (2 * tableSize) || (end - ptr) % (2 * tableSize)) { + dbug_unwind(1, "Bad num=%d end-ptr=%ld 2*tableSize=%d", num, end - ptr, 2 * tableSize); + return NULL; + } + + do { + const u8 *cur = ptr + (num / 2) * (2 * tableSize); + startLoc = read_pointer(&cur, cur + tableSize, hdr[3]); + if (pc < startLoc) + num /= 2; + else { + ptr = cur - tableSize; + num = (num + 1) / 2; + } + } while (startLoc && num > 1); + + if (num == 1 && (startLoc = read_pointer(&ptr, ptr + tableSize, hdr[3])) != 0 && pc >= startLoc) + fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]); + + dbug_unwind(1, "returning %lx", fde); + return fde; +} + +/* Unwind to previous to frame. Returns 0 if successful, negative + * number in case of an error. */ +int unwind(struct unwind_frame_info *frame) +{ +#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) + const u32 *fde, *cie = NULL; + const u8 *ptr = NULL, *end = NULL; + unsigned long pc = UNW_PC(frame) - frame->call_frame; + unsigned long tableSize, startLoc = 0, endLoc = 0, cfa; + unsigned i; + signed ptrType = -1; + uleb128_t retAddrReg = 0; + struct _stp_module *m; + struct unwind_state state; + + dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame)); + + if (UNW_PC(frame) == 0) + return -EINVAL; + + m = _stp_get_unwind_info(pc); + if (unlikely(m == NULL)) { + dbug_unwind(1, "No module found for pc=%lx", pc); + return -EINVAL; + } + + if (unlikely(m->unwind_data_len == 0 || m->unwind_data_len & (sizeof(*fde) - 1))) { + dbug_unwind(1, "Module %s: unwind_data_len=%d", m->name, m->unwind_data_len); + goto done; + } + + fde = _stp_search_unwind_hdr(pc, m); + dbug_unwind(1, "%s: fde=%lx\n", m->name, fde); + + if (fde != NULL) { + cie = cie_for_fde(fde, m); + ptr = (const u8 *)(fde + 2); + if (cie != NULL + && cie != &bad_cie + && cie != ¬_fde + && (ptrType = fde_pointer_type(cie)) >= 0 + && read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType) == startLoc) { + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; + endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); + if (pc >= endLoc) + fde = NULL; + } else + fde = NULL; + } + if (fde == NULL) { + for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde) + && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { + // dbug_unwind(1,"fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize); + cie = cie_for_fde(fde, m); + if (cie == &bad_cie) { + cie = NULL; + break; + } + if (cie == NULL || cie == ¬_fde || (ptrType = fde_pointer_type(cie)) < 0) + continue; + + ptr = (const u8 *)(fde + 2); + startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); + // dbug_unwind(1,"startLoc=%p\n",(u64)startLoc); + if (!startLoc) + continue; + if (!(ptrType & DW_EH_PE_indirect)) + ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; + endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); + // dbug_unwind(1,"endLoc=%p\n",(u64)endLoc); + if (pc >= startLoc && pc < endLoc) + break; + } + } + + dbug_unwind(1, "cie=%lx fde=%lx startLoc=%lx endLoc=%lx\n", cie, fde, startLoc, endLoc); + if (cie == NULL || fde == NULL) + goto done; + + /* found the CIE and FDE */ + + memset(&state, 0, sizeof(state)); + state.cieEnd = ptr; /* keep here temporarily */ + ptr = (const u8 *)(cie + 2); + end = (const u8 *)(cie + 1) + *cie; + frame->call_frame = 1; + if ((state.version = *ptr) != 1) { + dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version); + goto done; /* unsupported version */ + } + if (*++ptr) { + /* check if augmentation size is first (and thus present) */ + if (*ptr == 'z') { + while (++ptr < end && *ptr) { + switch (*ptr) { + /* check for ignorable (or already handled) + * nul-terminated augmentation string */ + case 'L': + case 'P': + case 'R': + continue; + case 'S': + frame->call_frame = 0; + continue; + default: + break; + } + break; + } + } + if (ptr >= end || *ptr) { + dbug_unwind(1, "Problem parsing the augmentation string.\n"); + goto done; + } + } + ++ptr; + + /* get code aligment factor */ + state.codeAlign = get_uleb128(&ptr, end); + /* get data aligment factor */ + state.dataAlign = get_sleb128(&ptr, end); + if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) + goto done;; + + retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); + + /* skip augmentation */ + if (((const char *)(cie + 2))[1] == 'z') { + uleb128_t augSize = get_uleb128(&ptr, end); + ptr += augSize; + } + if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info) + || REG_INVALID(retAddrReg) + || reg_info[retAddrReg].width != sizeof(unsigned long)) + goto done; + + state.cieStart = ptr; + ptr = state.cieEnd; + state.cieEnd = end; + end = (const u8 *)(fde + 1) + *fde; + + /* skip augmentation */ + if (((const char *)(cie + 2))[1] == 'z') { + uleb128_t augSize = get_uleb128(&ptr, end); + if ((ptr += augSize) > end) + goto done; + } + + state.org = startLoc; + memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); + /* process instructions */ + if (!processCFI(ptr, end, pc, ptrType, &state) + || state.loc > endLoc || state.regs[retAddrReg].where == Nowhere || state.cfa.reg >= ARRAY_SIZE(reg_info) + || reg_info[state.cfa.reg].width != sizeof(unsigned long) + || state.cfa.offs % sizeof(unsigned long)) + goto done; + + /* update frame */ + dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde); +#ifndef CONFIG_AS_CFI_SIGNAL_FRAME + if (frame->call_frame && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign)) + frame->call_frame = 0; +#endif + cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; + startLoc = min((unsigned long)UNW_SP(frame), cfa); + endLoc = max((unsigned long)UNW_SP(frame), cfa); + dbug_unwind(1, "cfa=%lx SP startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc); + if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) { + startLoc = min(STACK_LIMIT(cfa), cfa); + endLoc = max(STACK_LIMIT(cfa), cfa); + dbug_unwind(1, "SP startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc); + } +#ifndef CONFIG_64BIT +# define CASES CASE(8); CASE(16); CASE(32) +#else +# define CASES CASE(8); CASE(16); CASE(32); CASE(64) +#endif + dbug_unwind(1, "cie=%p fde=%p\n", (u64)cie, (u64)fde); + for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { + if (REG_INVALID(i)) { + if (state.regs[i].where == Nowhere) + continue; + dbug_unwind(1, "REG_INVALID %d\n", i); + goto done; + } + dbug_unwind(1, "register %d. where=%d\n", i, state.regs[i].where); + switch (state.regs[i].where) { + default: + break; + case Register: + if (state.regs[i].value >= ARRAY_SIZE(reg_info) + || REG_INVALID(state.regs[i].value) + || reg_info[i].width > reg_info[state.regs[i].value].width) { + dbug_unwind(1, "case Register bad\n"); + goto done; + } + switch (reg_info[state.regs[i].value].width) { +#define CASE(n) \ + case sizeof(u##n): \ + state.regs[i].value = FRAME_REG(state.regs[i].value, \ + const u##n); \ + break + CASES; +#undef CASE + default: + dbug_unwind(1, "default\n"); + goto done; + } + break; + } + } + for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { + dbug_unwind(1, "register %d. invalid=%d\n", i, REG_INVALID(i)); + if (REG_INVALID(i)) + continue; + dbug_unwind(1, "register %d. where=%d\n", i, state.regs[i].where); + switch (state.regs[i].where) { + case Nowhere: + if (reg_info[i].width != sizeof(UNW_SP(frame)) + || &FRAME_REG(i, __typeof__(UNW_SP(frame))) + != &UNW_SP(frame)) + continue; + UNW_SP(frame) = cfa; + break; + case Register: + switch (reg_info[i].width) { +#define CASE(n) case sizeof(u##n): \ + FRAME_REG(i, u##n) = state.regs[i].value; \ + break + CASES; +#undef CASE + default: + dbug_unwind(1, "default\n"); + goto done; + } + break; + case Value: + if (reg_info[i].width != sizeof(unsigned long)) { + dbug_unwind(1, "Value\n"); + goto done; + } + FRAME_REG(i, unsigned long) = cfa + state.regs[i].value * state.dataAlign; + break; + case Memory:{ + unsigned long addr = cfa + state.regs[i].value * state.dataAlign; + dbug_unwind(1, "addr=%lx width=%d\n", addr, reg_info[i].width); + switch (reg_info[i].width) { +#define CASE(n) case sizeof(u##n): \ + if (unlikely(__stp_get_user(FRAME_REG(i, u##n), (u##n *)addr))) \ + goto copy_failed;\ + dbug_unwind(1, "set register %d to %lx\n", i, (long)FRAME_REG(i,u##n));\ + break + CASES; +#undef CASE + default: + dbug_unwind(1, "default\n"); + goto done; + } + } + break; + } + } + read_unlock(&m->lock); + dbug_unwind(1, "returning 0 (%lx)\n", UNW_PC(frame)); + return 0; + +copy_failed: + dbug_unwind(1, "_stp_get_user failed to access memory\n"); +done: + read_unlock(&m->lock); + return -EIO; +#undef CASES +#undef FRAME_REG +} diff --git a/runtime/uprobes/Makefile b/runtime/uprobes/Makefile deleted file mode 100644 index 40af7aa2..00000000 --- a/runtime/uprobes/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -obj-m := uprobes.o -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) -DEPENDENCIES := $(shell echo uprobes_arch.[ch] uprobes.[ch] uprobes_*.[ch]) -DEPENDENCIES += Makefile $(KDIR)/Module.symvers - -default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules - -# This target is used with "make -q" to see whether a "real" build is needed. -uprobes.ko: $(DEPENDENCIES) - @echo uprobes.ko is not a valid target. See Makefile. - -clean: - rm -f *.mod.c *.ko *.o .*.cmd *~ - rm -rf .tmp_versions diff --git a/safety/README b/safety/README deleted file mode 100644 index 61eda4a2..00000000 --- a/safety/README +++ /dev/null @@ -1,10 +0,0 @@ -This is a static safety-checker for SystemTap modules. It attempts to -validate modules by checking the opcodes used and the external references -against a whitelist. - -The script relies on external data files to provide the whitelists, which by -default are in the /data directory. The 'references' file -provides a plain list of allowed references. The 'opcodes' file provides a -list of regular expressions that match allowed opcodes. Either data file may -have an optional kernel and/or architecture suffix, as in 'opcodes-i686' or -'references-2.6.9-32.ELsmp-x86_64'. diff --git a/safety/data/opcodes-i686 b/safety/data/opcodes-i686 deleted file mode 100644 index 123fa2b0..00000000 --- a/safety/data/opcodes-i686 +++ /dev/null @@ -1,107 +0,0 @@ -aaa -aad -aam -aas -adc[bwl]? -add[bwl]? -and[bwl]? -bound[wl]? -bsf[wl]? -bsr[wl]? -bswapl? -btc[wl]? -btr[wl]? -bts[wl]? -bt[wl]? -call -cbtw -cbw -cdq -clc -cld -cli -cltd -cmc -cmovn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z)[wl]? -cmp[bwl]? -cmps[bwl]? -cmpxchg8b -cmpxchg[bwl]? -cpuid -cwd -cwde -cwtd -cwtl -daa -das -dec[bwl]? -div[bwl]? -enter -idiv[bwl]? -imul[bwl]? -inc[bwl]? -je?cxz -jmp -jn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z) -lcall -lds[wl]? -leave -lea[wl]? -les[wl]? -lfence -lfs[wl]? -lgs[wl]? -lods[bwl]? -loopn?[ze]? -lret -lss[wl]? -mfence -movaps -mov[bwl]? -movs[bwl]? -movsb[wl]? -movswl? -movzb[wl]? -movzwl? -mul[bwl]? -neg[bwl]? -nop -not[bwl]? -or[bwl]? -pause -popa[wl]? -popf[wl]? -pop[wl]? -prefetch(?:t[012]|nta) -pusha[wl]? -pushf[wl]? -push[wl]? -rcl[bwl]? -rcr[bwl]? -rdmsr -rdtsc -ret -rol[bwl]? -ror[bwl]? -sahf -sal[bwl]? -sar[bwl]? -sbb[bwl]? -scas[bwl]? -setn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z) -shl[bwl]? -shld[bwl]? -shr[bwl]? -shrd[bwl]? -smov[lw]? -stc -std -sti -stos[bwl]? -sub[bwl]? -test[bwl]? -xadd[bwl]? -xchg[bwl]? -xlat -xlatb -xor[bwl]? diff --git a/safety/data/opcodes-ia64 b/safety/data/opcodes-ia64 deleted file mode 100644 index edb1792e..00000000 --- a/safety/data/opcodes-ia64 +++ /dev/null @@ -1,89 +0,0 @@ -add[sl]? -addp4 -alloc -and -andcm -br(?:\.cond)?(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.cond(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.call(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.ret(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.cloop(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.ctop(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.cexit(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.wtop(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -br\.wexit(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -brl(?:\.cond)?(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -brl\.call(?:\.(?:spnt|sptk|dpnt|dptk))?(?:\.(?:few|many))?(?:\.clr)? -brp(?:\.(?:sptk|loop|exit|dptk))(?:\.imp)? -brp\.ret(?:\.(?:sptk|loop|exit|dptk))(?:\.imp)? -chk\.s(?:\.[im])? -chk\.a\.(?:clr|nc) -clrrrb -cmp\.(?:eq|ne|l[te]u?|g[te]u?)(?:\.(?:unc|or|and|or.andcm|orcm|andcm|and.orcm))? -cmp4\.(?:eq|ne|l[te]u?|g[te]u?)(?:\.(?:unc|or|and|or.andcm|orcm|andcm|and.orcm))? -cmpxchg[1248]\.(?:acq|rel)(?:\.nt[1a])? -cmp8xchg16\.(?:acq|rel)(?:\.nt[1a])? -cover -czx[12]\.[lr] -dep(?:\.z)? -extr(?:\.u)? -fetchadd[48]\.(?:acq|rel)(?:\.nt[1a])? -getf\.(?:s|d|exp|sig) -hint(?:\.[ibmfx])? -ld[1248](?:\.(?:s|a|sa|c\.nc|c\.clr|c\.clr\.acq|acq|bias))?(?:\.nt[1a])? -ld8\.fill(?:\.nt[1a])? -ld16(?:\.acq)?(?:\.nt[1a])? -ldf8(?:\.(?:s|a|sa|c\.nc|c\.clr))?(?:\.nt[1a])? -lfetch(?:.fault)?(?:\.excl)?(?:\.nt[12a])? -mf -mix[124]\.[lr] -mov(?:\.[im])? -mov(?:\.ret)?(?:\.sptk|\.dptk)?(?:\.imp)? -movl -mux[12] -nop(?:\.[ibmfx])? -or -pack2\.[us]ss -pack4.sss -padd[124] -padd[12]\.(?:sss|uus|uuu) -pavg[12](?:\.raz) -pavgsub[12] -pcmp[124]\.(?:eq|gt) -pmax1\.u -pmax2 -pmin1\.u -pmin2 -pmpy2\.[rl] -pmpyshr2(?:\.u)? -popcnt -psad1 -pshl[24] -pshladd2 -pshr[24](?:\.u)? -pshradd2 -psub[124] -psub[12]\.(?:sss|uus|uuu) -rsm -setf\.(?:s|d|exp|sig) -shl -shladd -shladdp4 -shr(?:\.u)? -shrp -srlz\.[id] -ssm -st[1248](?:\.rel)?(?:\.nta)? -st16(?:\.rel)?(?:\.nta)? -st8\.spill(?:\.nta)? -stf8(?:\.nta)? -sub -sxt[124] -tbit\.n?z(?:\.(?:unc|or|and|or.andcm|orcm|andcm|and.orcm))? -tnat\.n?z(?:\.(?:unc|or|and|or.andcm|orcm|andcm|and.orcm))? -unpack[124]\.[hl] -xchg[1248](?:\.nt[1a])? -xma\.[lh]u? -xmpy\.[lh]u? -xor -zxt[124] diff --git a/safety/data/opcodes-x86_64 b/safety/data/opcodes-x86_64 deleted file mode 100644 index b89df879..00000000 --- a/safety/data/opcodes-x86_64 +++ /dev/null @@ -1,104 +0,0 @@ -adc[bwlq]? -add[bwlq]? -and[bwlq]? -boundl? -bsf[wlq]? -bsr[wlq]? -bswap[lq]? -btc[wlq]? -btr[wlq]? -bts[wlq]? -bt[wlq]? -callq? -cbtw -cbw -cdq -cdqe -clc -cld -cli -cltd -cltq -cmc -cmovn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z)[wlq]? -cmp[bwlq]? -cmps[bwlq]? -cmpxchg16b -cmpxchg8b -cmpxchg[bwlq]? -cpuid -cqo -cqtd -cqto -cwd -cwde -cwtd -cwtl -dec[bwlq]? -div[bwlq]? -enterq? -idiv[bwlq]? -imul[bwlq]? -inc[bwlq]? -jcxz -jmpq? -jn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z) -lcallq? -leaveq? -lea[wlq]? -lfence -lfs[wl]? -lgs[wl]? -lods[bwlq]? -loopn?[ze]? -lretq? -lss[wl]? -mfence -movaps -mov[bwlq]? -movs[bwlq]? -movsb[wlq]? -movslq? -movsw[lq]? -movzb[wlq]? -movzw[lq]? -mul[bwlq]? -neg[bwlq]? -nop -not[bwlq]? -or[bwlq]? -pause -popf[wlq]? -pop[wlq]? -prefetch(?:t[012]|nta) -pushf[wlq]? -push[wlq]? -rcl[bwlq]? -rcr[bwlq]? -rdmsr -rdtsc -retq? -rol[bwlq]? -ror[bwlq]? -sahf -sal[bwlq]? -sar[bwlq]? -sbb[bwlq]? -scas[bwlq]? -setn?(?:a|ae|b|be|c|e|g|ge|l|le|o|p|pe|po|s|z) -shl[bwlq]? -shld[bwlq]? -shr[bwlq]? -shrd[bwlq]? -smov[lw]? -stc -std -sti -stos[bwlq]? -sub[bwlq]? -test[bwlq]? -xadd[bwlq]? -xchg[bwlq]? -xlat -xlatb -xor[bwlq]? diff --git a/safety/data/references b/safety/data/references deleted file mode 100644 index bfea8e86..00000000 --- a/safety/data/references +++ /dev/null @@ -1,94 +0,0 @@ -__alloc_percpu -autoremove_wake_function -__bitmap_weight -cond_resched -__const_udelay -copy_from_user -__copy_from_user_ll -copy_to_user -__copy_user -copy_user_generic -cpu_callout_map -cpu_online_map -cpu_possible_map -cpu_to_node -create_proc_entry -del_timer_sync -__divdi3 -do_gettimeofday -__down_failed -__find_next_bit -find_next_bit -finish_wait -free_percpu -__get_user_4 -init_timer -__init_timer_base -jiffies -kallsyms_lookup_name -kfree -__kmalloc -kmalloc_node -kmem_cache_alloc -malloc_sizes -memcmp -memcpy -memset -__might_sleep -__moddi3 -__mod_timer -mod_timer -msleep -node_online_map -param_get_int -param_get_long -param_get_string -param_set_copystring -param_set_int -param_set_long -per_cpu__cpu_info -prepare_to_wait -printk -proc_mkdir -proc_root -_read_lock -_read_trylock -_read_unlock -register_kprobe -register_kretprobe -register_profile_notifier -register_timer_hook -remove_proc_entry -schedule -schedule_delayed_work -scnprintf -simple_strtol -snprintf -_spin_lock -_spin_lock_irqsave -_spin_trylock -_spin_unlock -_spin_unlock_irqrestore -sprintf -strcmp -strlcat -strlcpy -strlen -strncmp -strncpy -__strncpy_from_user -strsep -__udivdi3 -__umoddi3 -unregister_kprobe -unregister_kretprobe -unregister_profile_notifier -unregister_timer_hook -unw_init_running -unw_unwind -__up_wakeup -vscnprintf -vsnprintf -__wake_up -_write_trylock -_write_unlock diff --git a/safety/safety.py b/safety/safety.py deleted file mode 100755 index 8607ce75..00000000 --- a/safety/safety.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# vim: noet sw=4 ts=4 enc=utf-8 -"A static safety-checker for SystemTap modules." - -# 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. - - -# in python 2.4, set & frozenset are builtins -# in python 2.3, the equivalents live in the 'sets' module -from sys import hexversion as __hexversion -if __hexversion < 0x020400f0: - from sets import Set as set, ImmutableSet as frozenset - - -def main(argv): - """ - CLI to the SystemTap static safety-checker. - - Provides a command-line interface for running the SystemTap module - safety checker. Use '-h' or '--help' for a description of the - command-line options. - - Returns the number of modules that failed the check. - """ - bad = 0 - (options, args) = __parse_args(argv[1:]) - safe = StaticSafety(options.arch, options.release, options.datapath) - for m in args: - if not safe.check_module(m): - bad += 1 - return bad - - -def __parse_args(argv): - from optparse import OptionParser - parser = OptionParser(usage="usage: %prog [options] [module]...", - description=__doc__) - parser.add_option('--data-path', dest='datapath', metavar='PATH', - help='specify the whitelist data files [default: /data]') - parser.add_option('-m', '--machine', '--architecture', dest='arch', - help='specify the machine architecture of the target') - parser.add_option('-r', '--kernel-release', dest='release', - help='specify the kernel release running on the target') - return parser.parse_args(argv) - - -class StaticSafety: - "Manage a safety-checking session." - - def __init__(self, arch=None, release=None, datapath=None): - from os import uname - self.__arch = arch or uname()[4] - self.__release = release or uname()[2] - self.__build_data_path(datapath) - self.__build_search_suffixes() - self.__load_allowed_references() - self.__load_allowed_opcodes() - - def __build_data_path(self, datapath): - "Determine where the data directory resides." - from sys import argv - from os.path import dirname, isdir, realpath - if datapath is None: - local = dirname(realpath(argv[0])) - self.__data_path = local + '/data' - else: - self.__data_path = datapath - - if not isdir(self.__data_path): - raise StandardError( - "Can't find the data directory! (looking in %s)" - % self.__data_path) - - def __build_search_suffixes(self): - "Construct arch & kernel-versioning search suffixes." - ss = set() - - # add empty string - ss.add('') - - # add architecture search path - archsfx = '-%s' % self.__arch - ss.add(archsfx) - - # add full kernel-version-release (2.6.NN-FOOBAR) + arch - relsfx = '-%s' % self.__release - ss.add(relsfx) - ss.add(relsfx + archsfx) - - # add kernel version (2.6.NN) + arch - dash_i = relsfx.find('-') - if dash_i > 0: - ss.add(relsfx[:dash_i]) - ss.add(relsfx[:dash_i] + archsfx) - - # start dropping decimals - dot_i = relsfx.rfind('.', 0, dash_i) - while dot_i > 0: - ss.add(relsfx[:dot_i]) - ss.add(relsfx[:dot_i] + archsfx) - dot_i = relsfx.rfind('.', 0, dot_i) - - self.__search_suffixes = frozenset(ss) - - def __load_allowed_references(self): - "Build the list of allowed external references from the data files." - wr = set() - for sfx in self.__search_suffixes: - try: - refs = open(self.__data_path + '/references' + sfx) - for line in refs: - wr.add(line.rstrip()) - refs.close() - except IOError: - pass - if not len(wr): - raise StandardError("No whitelisted references found!") - self.__white_references = frozenset(wr) - - def __load_allowed_opcodes(self): - "Build the regular expression matcher for allowed opcodes from the data files." - from re import compile - wo = [] - for sfx in self.__search_suffixes: - try: - opcs = open(self.__data_path + '/opcodes' + sfx) - for line in opcs: - wo.append(line.rstrip()) - opcs.close() - except IOError: - pass - if not len(wo): - raise StandardError("No whitelisted opcodes found!") - self.__white_opcodes_re = compile(r'^(?:' + r'|'.join(wo) + r')$') - - def __check_references(self, module): - "Check that all unresolved references in the module are allowed." - from os import popen - from re import compile - - sym_re = compile(r'^([\w@.]+) [Uw]\s+$') - def check(line): - m = sym_re.match(line) - if m: - ref = m.group(1) - if ref not in self.__white_references: - print 'ERROR: Invalid reference to %s' % ref - return False - return True - print 'WARNING: Unmatched line:\n %s' % `line` - return True - - command = 'nm --format=posix --no-sort --undefined-only ' + `module` - ok = True - nm = popen(command) - for line in nm: - ok &= check(line) - if nm.close(): - ok = False - return ok - - def __check_opcodes(self, module): - "Check that all disassembled opcodes in the module are allowed." - from os import popen - from re import compile - - skip_ud2a = [0] - - ignore_re = compile(r'^$|^\s+\.{3}$|^.*Disassembly of section|^.*file format') - if self.__arch == 'ia64': - opc = r'(?:\[[IBFLMX]{3}\]\s+)?(?:\(p\d\d\)\s+)?([\w.]+)\b' - elif self.__arch == 'x86_64' or self.__arch == 'i686': - opc = r'(?:lock\s+)?|(?:repn?[ze]?\s+)?|(?:rex\w+\s+)?(\w+)\b' - else: - opc = r'(\w+)\b' - opc_re = compile(r'^[A-Fa-f\d]+\s+<([^>]+)>\s+%s' % opc) - def check(line): - m = ignore_re.match(line) - if m: - return True - m = opc_re.match(line) - if m: - loc, opc = m.groups() - if opc == 'ud2a': - # The kernel abuses ud2a for BUG checks by following it - # directly with __LINE__ and __FILE__. Objdump doesn't - # know this though, so it tries to interpret the data as - # real instructions. Because x86(-64) instructions are - # variable-length, it's hard to tell when objdump is synced - # up again. We'll fast-forward to the next function - # boundary and hope things are better there. - for skip in objdump: - mskip = opc_re.match(skip) - if mskip: - locskip = mskip.group(1) - # a loc without an offset marks a new function - if '+' not in locskip: - return check(skip) - skip_ud2a[0] += 1 - return True - elif not self.__white_opcodes_re.match(opc): - print "ERROR: Invalid opcode '%s' at <%s>" % (opc, loc) - return False - return True - print 'WARNING: Unmatched line:\n %s' % `line` - return True - - command = 'objdump --disassemble --prefix-addresses ' + `module` - ok = True - objdump = popen(command) - for line in objdump: - ok &= check(line) - if objdump.close(): - ok = False - - if skip_ud2a[0]: - #print 'WARNING: Skipped %d lines due to ud2a corruption' % skip_ud2a[0] - pass - - return ok - - def check_module(self, module): - "Check a module for exclusively safe opcodes and external references." - from os.path import isfile - if not isfile(module): - print 'ERROR: %s is not a file!' % `module` - return False - res = self.__check_references(module) and self.__check_opcodes(module) - if res: - print 'PASS: %s' % module - else: - print 'FAIL: %s' % module - return res - - -if __name__ == '__main__': - from sys import exit, argv - exit(main(argv)) - diff --git a/stap.1.in b/stap.1.in index acfc64c3..c557350a 100644 --- a/stap.1.in +++ b/stap.1.in @@ -467,12 +467,11 @@ For prologue style alias, the statement block that follows an alias definition is implicitly added as a prologue to any probe that refers to the alias. While for the epilogue style alias, the statement block that follows an alias definition is implicitly added as an epilogue to -any probe that refers to the alias. For example: +any probe that refers to the alias. For example: .SAMPLE probe syscall.read = kernel.function("sys_read") { fildes = $fd - if (execname == "init") next # skip rest of probe } .ESAMPLE defines a new probe point @@ -483,23 +482,19 @@ which expands to .nh .IR kernel.function("sys_read") , .hy -with the given statement as a prologue, which is useful to predefine -some variables for the alias user and/or to skip probe processing -entirely based on some conditions. And +with the given statement as a prologue. And .SAMPLE probe syscall.read += kernel.function("sys_read") { - if (tracethis) println ($fd) + fildes = $fd } .ESAMPLE -defines a new probe point with the given statement as an epilogue, which -is useful to take actions based upon variables set or left over by the -the alias user. +defines a new probe point with the given statement as an epilogue. -An alias is used just like a built-in probe type. +Another probe definition +may use the alias like this: .SAMPLE probe syscall.read { printf("reading fd=%d\n", fildes) - if (fildes > 10) tracethis = 1 } .ESAMPLE diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 9bca845d..85a00b37 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -92,60 +92,6 @@ fault, return instead the err_msg value. user_string_warn:string (addr:long) Copy a string from user space at given address. If the access would fault, signal a warning and return "". -.TP -user_string_quoted:string (addr:long) -Copy a string from user space at given address. Any ASCII characters -that are not printable are replaced by the corresponding escape -sequence in the returned string. -.TP -user_string_n:string (addr:long, n:long) -Copy a string of n bytes from user space at given address. If the access -would fault, return "". -.TP -user_string_n2:string (addr:long, n:long, err_msg:string) -Copy a string of n bytes from user space at given address. If the access -would fault, return the err_msg value. -.TP -user_string_n_warn:string (addr:long, n:long) -Copy a string of n bytes from user space at given address. If the access -would fault, signal a warning and return "". -.TP -user_string_n_quoted:string (addr:long, n:long) -Copy a string of n bytes from user space at given address. Any ASCII -characters that are not printable are replaced by the corresponding escape -sequence in the returned string. If the access would fault, return "". -.TP -user_short:long (addr:long) -Copy a short from user space at given address. If the access would fault, -return 0. -.TP -user_short_warn:long (addr:long) -Copy a short from user space at given address. If the access would fault, -signal a warning and return 0. -.TP -user_int:long (addr:long) -Copy an int from user space at given address. If the access would fault, -return 0. -.TP -user_int_warn:long (addr:long) -Copy an int from user space at given address. If the access would fault, -signal a warning and return 0. -.TP -user_long:long (addr:long) -Copy a long from user space at given address. If the access would fault, -return 0. -.TP -user_long_warn:long (addr:long) -Copy a long from user space at given address. If the access would fault, -signal a warning and return 0. -.TP -user_char:long (addr:long) -Copy a char from user space at given address. If the access would fault, -return 0. -.TP -user_char_warn:long (addr:long) -Copy a char from user space at given address. If the access would fault, -signal a warning and return 0. .SS STRING .TP strlen:long (str:string) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index dae8b452..da21a5ff 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,11 +1,3 @@ -2008-03-21 Eugene Teo - - PR 5528 - * conversions.stp (user_string_n, user_string_n2, user_string_n_warn, - user_string_n_quoted, user_short, user_short_warn, user_int, - user_int_warn, user_long, user_long_warn, user_char, user_char_warn): - New user_* functions. - 2008-03-20 Frank Ch. Eigler PR 5956. diff --git a/tapset/conversions.stp b/tapset/conversions.stp index 70725e9d..af993992 100644 --- a/tapset/conversions.stp +++ b/tapset/conversions.stp @@ -1,5 +1,5 @@ // conversions tapset -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2007 Red Hat Inc. // Copyright (C) 2007 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -108,131 +108,3 @@ function user_string_quoted:string (addr:long) %{ /* pure */ _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, MAXSTRINGLEN, 1, 1); %} - -function user_string_n:string (addr:long, n:long) { - return user_string_n2(addr, n, "") -} - -function user_string_n2:string (addr:long, n:long, err_msg:string) %{ /* pure */ - long len = THIS->n + 1; - len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; - if (_stp_strncpy_from_user(THIS->__retvalue, - (char __user *) (uintptr_t) THIS->addr, - len) < 0) - strlcpy(THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN); -%} - -function user_string_n_warn:string (addr:long, n:long) %{ /* pure */ - long len = THIS->n + 1; - long rc; - - len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; - rc = _stp_strncpy_from_user(THIS->__retvalue, - (char __user *) (uintptr_t) THIS->addr, len); - if (rc < 0) { - // NB: using error_buffer to get local space for the warning, but we're - // not aborting, so leave last_error alone. - snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "user string copy fault %ld at %p", rc, - (void *) (uintptr_t) THIS->addr); - _stp_warn(CONTEXT->error_buffer); - strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); - } -%} - -function user_string_n_quoted:string (addr:long, n:long) %{ /* pure */ - long len = THIS->n + 1; - if (THIS->addr == 0) - strlcpy(THIS->__retvalue, "NULL", MAXSTRINGLEN); - else - /* XXX: stp_text_str uses sleepy __get_user() => unsafe ?! */ - _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, - len, 1, 1); -%} - -// When userspace data is not accessible, the following functions return 0 - -function user_short:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { -fault: - THIS->__retvalue = 0; - } -%} - -function user_short_warn:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { -fault: - snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "user short copy fault %p", (void *) (uintptr_t) THIS->addr); - _stp_warn(CONTEXT->error_buffer); - THIS->__retvalue = 0; - } -%} - -function user_int:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { -fault: - THIS->__retvalue = 0; - } -%} - -function user_int_warn:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { -fault: - snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "user int copy fault %p", (void *) (uintptr_t) THIS->addr); - _stp_warn(CONTEXT->error_buffer); - THIS->__retvalue = 0; - } -%} - -function user_long:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { -fault: - THIS->__retvalue = 0; - } -%} - -function user_long_warn:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { -fault: - snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "user long copy fault %p", (void *) (uintptr_t) THIS->addr); - _stp_warn(CONTEXT->error_buffer); - THIS->__retvalue = 0; - } -%} - -function user_char:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { -fault: - THIS->__retvalue = 0; - } -%} - -function user_char_warn:long (addr:long) %{ /* pure */ - if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) - goto fault; - if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { -fault: - snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "user char copy fault %p", (void *) (uintptr_t) THIS->addr); - _stp_warn(CONTEXT->error_buffer); - THIS->__retvalue = 0; - } -%} - diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index a54e80bd..16f7af57 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,21 +1,3 @@ -2008-03-23 Frank Ch. Eigler - - * lib/stap_run.exp (stap_run): Ignore missing debuginfo warnings. - Try harder to kill stap child in case of timeouts and errors. - -2008-03-23 Frank Ch. Eigler - - PR 5980. - * lib/systemtap.exp: Set default Snapshot: value from "stap -V" - output. - -2008-03-21 Eugene Teo - - PR 5528 - * systemtap.stress/conversions.stp: Test new user_* functions. - * buildok/conversions.stp: Test new user_* functions. - * buildok/conversions-embedded.stp: Test new user_* functions. - 2008-03-20 Frank Ch. Eigler PR 5956. diff --git a/testsuite/buildok/conversions-embedded.stp b/testsuite/buildok/conversions-embedded.stp index 55f6cdb7..7aa5a0b4 100755 --- a/testsuite/buildok/conversions-embedded.stp +++ b/testsuite/buildok/conversions-embedded.stp @@ -9,18 +9,5 @@ probe begin { print (user_string2 (0, "")) print (user_string_warn (0)) print (user_string_quoted (0)) - - print (user_string_n(0, 5)) - print (user_string_n2(0, 5, "foobar")) - print (user_string_n_warn(0, 0)) - print (user_string_n_quoted(0, 0)) - print (user_short(0)) - print (user_short_warn(0)) - print (user_int(0)) - print (user_int_warn(0)) - print (user_long(0)) - print (user_long_warn(0)) - print (user_char(0)) - print (user_char_warn(0)) } diff --git a/testsuite/buildok/conversions.stp b/testsuite/buildok/conversions.stp index 5f151f1d..e83bd968 100755 --- a/testsuite/buildok/conversions.stp +++ b/testsuite/buildok/conversions.stp @@ -12,17 +12,4 @@ probe begin { print (user_string(2342)) print (user_string2(2342,"foobar")) print (user_string_warn(2342)) - - print (user_string_n(2342, 5)) - print (user_string_n2(2342, 5, "foobar")) - print (user_string_n_warn(2342, 5)) - print (user_string_n_quoted(2342, 5)) - print (user_short(2342)) - print (user_short_warn(2342)) - print (user_int(2342)) - print (user_int_warn(2342)) - print (user_long(2342)) - print (user_long_warn(2342)) - print (user_char(2342)) - print (user_char_warn(2342)) } diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index 42efa4f8..c2b4e74d 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -34,7 +34,6 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } expect { -timeout 180 -re {^Warning: using '-m' disables cache support.\r\n} {exp_continue} - -re {^WARNING: cannot find module [^\r]*DWARF[^\r]*\r\n} {exp_continue} -re {^Pass\ ([1234]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms\.\r\n} {set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"; exp_continue} -re {^Pass\ ([34]): using cached [^\r]+\r\n} @@ -74,22 +73,15 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } set skipped_probes $expect_out(2,string)} } } - timeout { - fail "$TEST_NAME shutdown (timeout)" - exec kill -INT -[exp_pid] - } + timeout { fail "$TEST_NAME shutdown (timeout)" } eof { fail "$TEST_NAME shutdown (eof)" } } } -re "semantic error:" { fail "$TEST_NAME compilation" } - timeout { - fail "$TEST_NAME startup (timeout)" - exec kill -INT -[exp_pid] - } + timeout { fail "$TEST_NAME startup (timeout)" + exec kill -INT [exp_pid] } eof { fail "$TEST_NAME startup (eof)" } } - # again for good measure - exec kill -INT -[exp_pid] catch close wait } diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index d458e98f..baed0e41 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -58,9 +58,8 @@ proc get_system_info {} { } elseif [file exists $env(SRCDIR)/../SNAPSHOT] { set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT] } else { - regexp {version [^)]*} [exec stap -V 2>@ stdout] version - set Snapshot $version - } + set Snapshot "unknown" + } set Distro "Linux" if [file exists /etc/fedora-release] {set Distro [exec /bin/cat /etc/fedora-release]} if [file exists /etc/redhat-release] {set Distro [exec /bin/cat /etc/redhat-release]} diff --git a/testsuite/systemtap.stress/conversions.stp b/testsuite/systemtap.stress/conversions.stp index 34bd0c28..07795a6d 100644 --- a/testsuite/systemtap.stress/conversions.stp +++ b/testsuite/systemtap.stress/conversions.stp @@ -13,16 +13,4 @@ probe begin { print (user_string ($1)) } probe begin { print (user_string2 ($1,"")) } probe begin { print (user_string_warn ($1)) } probe begin { print (user_string_quoted ($1)) } -probe begin { print (user_string_n ($1, 5)) } -probe begin { print (user_string_n2 ($1, 5, "")) } -probe begin { print (user_string_n_warn ($1, 5)) } -probe begin { print (user_string_n_quoted ($1, 5)) } -probe begin { print (user_short ($1)) } -probe begin { print (user_short_warn ($1)) } -probe begin { print (user_int ($1)) } -probe begin { print (user_int_warn ($1)) } -probe begin { print (user_long ($1)) } -probe begin { print (user_long_warn ($1)) } -probe begin { print (user_char ($1)) } -probe begin { print (user_char_warn ($1)) } probe begin(1) { print ("\n") exit () } diff --git a/translate.cxx b/translate.cxx index 2bfacefc..8b9dee54 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4356,80 +4356,43 @@ c_unparser::visit_hist_op (hist_op*) int emit_symbol_data (systemtap_session& s) { - int rc = 0; - // Instead of processing elf symbol tables, for now we just snatch - // /proc/kallsyms and convert it to our use. We need it sorted by - // address (so we can binary search) , and filtered (to show text - // symbols only), a task that we defer to grep(1) and sort(1). It - // may be useful to cache the symbols.sorted file, perhaps indexed - // by md5sum(/proc/modules), but let's not until this simple method - // proves too costly. LC_ALL=C is already set to avoid the - // excessive penalty of i18n code in some glibc/coreutils versions. - - string sorted_kallsyms = s.tmpdir + "/symbols.sorted"; - string sortcmd = "grep \" [AtT] \" /proc/kallsyms | "; - - if (s.symtab == false) - { - s.op->newline() << "/* filled in by runtime */"; - s.op->newline() << "struct stap_symbol *stap_symbols;"; - s.op->newline() << "unsigned stap_num_symbols;\n"; - return 0; - } + // /proc/kallsyms and convert it to our use. - sortcmd += "sort "; -#if __LP64__ - sortcmd += "-k 1,16 "; -#else - sortcmd += "-k 1,8 "; -#endif - sortcmd += "-s -o " + sorted_kallsyms; + unsigned i=0; + ifstream kallsyms("/proc/kallsyms"); + char kallsyms_outbuf [4096]; + ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str()); + kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf, + sizeof(kallsyms_outbuf)); - if (s.verbose>1) clog << "Running " << sortcmd << endl; - rc = system(sortcmd.c_str()); - if (rc == 0) + s.op->newline() << "\n\n#include \"stap-symbols.h\""; + kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {"; + string lastaddr, modules_op_addr; + + while (! kallsyms.eof()) { - ifstream kallsyms (sorted_kallsyms.c_str()); - char kallsyms_outbuf [4096]; - ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str()); - kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf, - sizeof(kallsyms_outbuf)); - - s.op->newline() << "\n\n#include \"stap-symbols.h\""; + string addr, type, sym; + kallsyms >> addr >> type >> sym >> ws; - unsigned i=0; - kallsyms_out << "struct stap_symbol _stp_stap_symbols [] = {"; - string lastaddr; - while (! kallsyms.eof()) + if (kallsyms.peek() == '[') + break; + + // NB: kallsyms includes some duplicate addresses + if ((type == "t" || type == "T" || type == "A") && lastaddr != addr) { - string addr, type, sym, module; - kallsyms >> addr >> type >> sym; - kallsyms >> ws; - if (kallsyms.peek() == '[') - { - string bracketed; - kallsyms >> bracketed; - module = bracketed.substr (1, bracketed.length()-2); - } - - // NB: kallsyms includes some duplicate addresses - if ((type == "t" || type == "T" || type == "A") && lastaddr != addr) - { - kallsyms_out << " { 0x" << addr << ", " - << "\"" << sym << "\", " - << "\"" << module << "\" }," - << "\n"; - lastaddr = addr; - i ++; - } + kallsyms_out << " { 0x" << addr << ", " << "\"" << sym << "\" },\n"; + lastaddr = addr; + i ++; } - kallsyms_out << "};\n"; - kallsyms_out << "struct stap_symbol *stap_symbols = _stp_stap_symbols;"; - kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n"; + else if (sym == "modules_op") + modules_op_addr = addr; } + kallsyms_out << "};\n"; + kallsyms_out << "unsigned _stp_num_kernel_symbols = " << i << ";\n"; + kallsyms_out << "unsigned long _stp_modules_op = 0x" << modules_op_addr << ";\n"; - return rc; + return (i == 0); } @@ -4515,7 +4478,7 @@ translate_pass (systemtap_session& s) s.op->newline() << "#include "; s.op->newline() << "#include "; s.op->newline() << "#include \"loc2c-runtime.h\" "; - + // XXX: old 2.6 kernel hack s.op->newline() << "#ifndef read_trylock"; s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })"; diff --git a/vim/filetype.vim b/vim/filetype.vim deleted file mode 100644 index 8c1fdfbd..00000000 --- a/vim/filetype.vim +++ /dev/null @@ -1,10 +0,0 @@ -" Vim support file to detect file types -" Language: SystemTap -" Maintainer: Josh Stone -" Last Change: 2005 Dec 16 -" Note: this overrides the default *.stp mapping to "Stored Procedures" -" It would be nice to find a way to intelligently detect this. - -" SystemTap scripts -au BufNewFile,BufRead *.stp setf stap - diff --git a/vim/ftplugin/stap.vim b/vim/ftplugin/stap.vim deleted file mode 100644 index de49a4f1..00000000 --- a/vim/ftplugin/stap.vim +++ /dev/null @@ -1,25 +0,0 @@ -" Vim filetype plugin file -" Language: SystemTap -" Maintainer: Josh Stone -" Last Change: 2005 Dec 15 - -" Only do this when not done yet for this buffer -if exists("b:did_ftplugin") - finish -endif - -" Don't load another plugin for this buffer -let b:did_ftplugin = 1 - -set cpo-=C - -let b:undo_ftplugin = "setl cin< fo< com<" - -setlocal cindent - -" Set 'formatoptions' to break comment lines but not other lines, -" and insert the comment leader when hitting or using "o". -setlocal fo-=t fo+=croql - -" Set 'comments' to format dashed lists in comments. -setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://,:# diff --git a/vim/indent/stap.vim b/vim/indent/stap.vim deleted file mode 100644 index 16658d6c..00000000 --- a/vim/indent/stap.vim +++ /dev/null @@ -1,35 +0,0 @@ -" Vim indent file -" Language: SystemTap -" Maintainer: Josh Stone -" Last Change: 2005 Dec 15 - -" Only load this indent file when no other was loaded. -if exists("b:did_indent") - finish -endif -let b:did_indent = 1 - -" SystemTap indenting works *mostly* the same as C, so this gets things pretty -" close. For 'real' SystemTap indenting, we would have to write a custom -" indentexpr function. - -" indenting is similar to C, so start there... -setlocal cindent - -" Statements don't require a ';', so don't indent following lines -setlocal cino=+0 - -" Known issues: -" - need to detect when following lines are a continuation of the previous -" statement, and indent appropriately. -" - one-liners with control flow try to indent the next line if there's no -" ';'. For example: -" if (my_condition) break -" do_work() -" The second line should not be indented. -" - The embedded-C braces do not line up correctly -" - Preprocessor braces don't line up correctly, and internals of the -" preprocessor aren't getting any special handling. -" - Embedded-C statements across multiple lines don't indent -" - '#' comments don't maintain indenting (they get treated like C -" preprocessor statements) diff --git a/vim/syntax/stap.vim b/vim/syntax/stap.vim deleted file mode 100644 index 86c7d260..00000000 --- a/vim/syntax/stap.vim +++ /dev/null @@ -1,97 +0,0 @@ -" Vim syntax file -" Language: SystemTap -" Maintainer: Josh Stone -" Last Change: 2005 Dec 20 - -" For version 5.x: Clear all syntax items -" For version 6.x: Quit when a syntax file was already loaded -if version < 600 - syn clear -elseif exists("b:current_syntax") - finish -endif - -syn keyword stapStatement contained break continue return next delete containedin=stapBlock -syn keyword stapRepeat contained while for foreach in containedin=stapBlock -syn keyword stapConditional contained if else containedin=stapBlock -syn keyword stapDeclaration global probe function -syn keyword stapType string long - -syn region stapProbeDec start="\"lc=5 end="{"me=s-1 contains=stapString,stapNumber -syn match stapProbe contained "\<\w\+\>" containedin=stapProbeDec - -syn region stapFuncDec start="\"lc=8 end=":\|("me=s-1 contains=stapString,stapNumber -syn match stapFuncCall contained "\<\w\+\ze\(\s\|\n\)*(" containedin=stapBlock -syn match stapFunc contained "\<\w\+\>" containedin=stapFuncDec,stapFuncCall - -syn match stapStat contained "@\<\w\+\ze\(\s\|\n\)*(" containedin=stapBlock - -" decimal number -syn match stapNumber "\<\d\+\>" containedin=stapBlock -" octal number -syn match stapNumber "\<0\o\+\>" contains=stapOctalZero containedin=stapBlock -" Flag the first zero of an octal number as something special -syn match stapOctalZero contained "\<0" -" flag an octal number with wrong digits -syn match stapOctalError "\<0\o*[89]\d*" containedin=stapBlock -" hex number -syn match stapNumber "0x\x\+\>" containedin=stapBlock - -syn region stapString oneline start=+"+ skip=+\\"+ end=+"+ containedin=stapBlock - -syn region stapPreProc fold start="%(" end="%)" contains=stapNumber,stapString containedin=ALL -syn keyword stapPreProcCond contained kernel_v kernel_vr arch containedin=stapPreProc - -syn include @C syntax/c.vim -syn keyword stapCMacro contained THIS CONTEXT containedin=@C,stapCBlock -syn region stapCBlock fold matchgroup=stapCBlockDelims start="%{"rs=e end="%}"re=s contains=@C - -syn region stapBlock fold matchgroup=stapBlockEnds start="{"rs=e end="}"re=s containedin=stapBlock - -syn keyword stapTodo contained TODO FIXME XXX - -syn match stapComment "#.*" contains=stapTodo containedin=stapBlock -syn match stapComment "//.*" contains=stapTodo containedin=stapBlock -syn region stapComment matchgroup=stapComment start="/\*" end="\*/" contains=stapTodo,stapCommentBad containedin=stapBlock -syn match stapCommentBad contained "/\*" - -" treat ^#! as special -syn match stapSharpBang "^#!.*" - - -" define the default highlighting -" For version 5.7 and earlier: only when not done already -" For version 5.8 and later: only when an item doesn't have highlightling yet -if version >= 508 || !exists("did_stap_syn_inits") - if version < 508 - let did_stap_syn_inits = 1 - command -nargs=+ HiLink hi link - else - command -nargs=+ HiLink hi def link - endif - - HiLink stapNumber Number - HiLink stapOctalZero PreProc " c.vim does it this way... - HiLink stapOctalError Error - HiLink stapString String - HiLink stapTodo Todo - HiLink stapComment Comment - HiLink stapCommentBad Error - HiLink stapSharpBang PreProc - HiLink stapCBlockDelims Special - HiLink stapCMacro Macro - HiLink stapStatement Statement - HiLink stapConditional Conditional - HiLink stapRepeat Repeat - HiLink stapType Type - HiLink stapProbe Function - HiLink stapFunc Function - HiLink stapStat Function - HiLink stapPreProc PreProc - HiLink stapPreProcCond Special - HiLink stapDeclaration Typedef - - delcommand HiLink -endif - -let b:current_syntax = "stap" -- cgit From 6043234f6d6efba366f67666b2197a47f5bdafce Mon Sep 17 00:00:00 2001 From: fche Date: Tue, 25 Mar 2008 12:23:18 +0000 Subject: * clarify utility of epilogue-type probe aliases in documentation 2008-03-25 Frank Ch. Eigler * stap.1.in: Clarify utility of epilogue type probe aliases. * langref.tex: Clarify utility of epilogue-type probe aliases. --- ChangeLog | 16 ++++++++++++++++ doc/ChangeLog | 4 ++++ doc/langref.tex | 24 ++++++++++-------------- stap.1.in | 17 +++++++++++------ 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index c7bb82c3..046804c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-03-25 Frank Ch. Eigler + + * stap.1.in: Clarify utility of epilogue type probe aliases. + +2008-03-21 Eugene Teo + + PR 5528 + * tapset/conversions.stp (user_string_n, user_string_n2, + user_string_n_warn, user_string_n_quoted, user_short, user_short_warn, + user_int, user_int_warn, user_long, user_long_warn, user_char, + user_char_warn): New user_* functions. + * stapfuncs.5.in: Documented the new functions. + * testsuite/systemtap.stress/conversions.stp: Test new functions. + * testsuite/buildok/conversions.stp: Test new functions. + * testsuite/buildok/conversions-embedded.stp: Test new functions. + 2008-03-20 Frank Ch. Eigler PR 5975. diff --git a/doc/ChangeLog b/doc/ChangeLog index 902e1d1e..e652078d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2008-03-25 Frank Ch. Eigler + + * langref.tex: Clarify utility of epilogue-type probe aliases. + 2008-03-04 David Smith * tutorial.tex: Made minor changes to remove warnings. diff --git a/doc/langref.tex b/doc/langref.tex index 5b91d01d..973769d4 100644 --- a/doc/langref.tex +++ b/doc/langref.tex @@ -230,7 +230,7 @@ This prints: \end{verbatim} \end{vindent} Any larger number input to the function may exceed the MAXACTION or MAXNESTING -limits, which will be caught by the parser and result in an error. For more +limits, which will be caught at run time and result in an error. For more about limits see Section~\ref{sub:SystemTap-safety}. \newpage{} \subsection{The stap command} @@ -436,8 +436,10 @@ probe syscall.read = kernel.function("sys_read") { \index{epilogue-style aliases} \index{+=} The statement block that follows an alias definition is implicitly added -as an epilogue to any probe that refers to the alias. The following is an -example: +as an epilogue to any probe that refers to the alias. It is not useful +to define new variable there (since no subsequent code will see it), but +rather the code can take action based upon variables left set by the +prologue or by the user code. The following is an example: \begin{vindent} \begin{verbatim} @@ -445,15 +447,15 @@ example: # epilogue. # probe syscall.read += kernel.function("sys_read") { - fildes = $fd + if (traceme) println ("tracing me") } \end{verbatim} \end{vindent} \subsubsection{Probe alias usage} -Another probe definition may use a previously defined alias. The following -is an example. +A probe alias is used the same way as any built-in probe type, by +naming it: \begin{vindent} \begin{verbatim} @@ -1027,12 +1029,6 @@ type conversions between strings and numbers. Inconsistent type-related use of identifiers signals an error. -\subsubsection{Numbers} -\index{numbers} -Numbers are 64-bit signed integers. The parser will also accept (and wrap -around) values above positive $2^{63}$. - - \subsubsection{Literals} \index{literals} Literals are either strings or integers. Literals can be expressed as decimal, @@ -1041,10 +1037,10 @@ octal, or hexadecimal, using C notation. Type suffixes (e.g., \emph{L} or \subsubsection{Integers\label{sub:Integers}} -\index{integers} +\index{integers} \index{numbers} Integers are decimal, hexadecimal, or octal, and use the same notation as in C. Integers are 64-bit signed quantities, although the parser also accepts -(and wraps around) values above positive $2^{63}$. +(and wraps around) values above positive $2^{63}$ but below $2^{64}$. \subsubsection{Strings\label{sub:Strings}} diff --git a/stap.1.in b/stap.1.in index c557350a..acfc64c3 100644 --- a/stap.1.in +++ b/stap.1.in @@ -467,11 +467,12 @@ For prologue style alias, the statement block that follows an alias definition is implicitly added as a prologue to any probe that refers to the alias. While for the epilogue style alias, the statement block that follows an alias definition is implicitly added as an epilogue to -any probe that refers to the alias. For example: +any probe that refers to the alias. For example: .SAMPLE probe syscall.read = kernel.function("sys_read") { fildes = $fd + if (execname == "init") next # skip rest of probe } .ESAMPLE defines a new probe point @@ -482,19 +483,23 @@ which expands to .nh .IR kernel.function("sys_read") , .hy -with the given statement as a prologue. And +with the given statement as a prologue, which is useful to predefine +some variables for the alias user and/or to skip probe processing +entirely based on some conditions. And .SAMPLE probe syscall.read += kernel.function("sys_read") { - fildes = $fd + if (tracethis) println ($fd) } .ESAMPLE -defines a new probe point with the given statement as an epilogue. +defines a new probe point with the given statement as an epilogue, which +is useful to take actions based upon variables set or left over by the +the alias user. -Another probe definition -may use the alias like this: +An alias is used just like a built-in probe type. .SAMPLE probe syscall.read { printf("reading fd=%d\n", fildes) + if (fildes > 10) tracethis = 1 } .ESAMPLE -- cgit From 949e84da2d80837b192209efb4122f2ff59ab54d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 25 Mar 2008 11:46:14 -0400 Subject: add (back) runtime/unwind files --- runtime/unwind/i386.h | 97 +++++++++++++++++++++++++++++++++ runtime/unwind/unwind.h | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ runtime/unwind/x86_64.h | 101 ++++++++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 runtime/unwind/i386.h create mode 100644 runtime/unwind/unwind.h create mode 100644 runtime/unwind/x86_64.h diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h new file mode 100644 index 00000000..de68c67b --- /dev/null +++ b/runtime/unwind/i386.h @@ -0,0 +1,97 @@ +#ifndef _STP_I386_UNWIND_H +#define _STP_I386_UNWIND_H + +/* + * Copyright (C) 2002-2006 Novell, Inc. + * Jan Beulich + * This code is released under version 2 of the GNU GPL. + */ + + +#include +#include +#include +#include + +/* these are simple for i386 */ +#define _stp_get_unaligned(ptr) (*(ptr)) +#define _stp_put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) + +struct unwind_frame_info +{ + struct pt_regs regs; + struct task_struct *task; + unsigned call_frame:1; +}; + +#define UNW_PC(frame) (frame)->regs.eip +#define UNW_SP(frame) (frame)->regs.esp +#ifdef CONFIG_FRAME_POINTER +#define UNW_FP(frame) (frame)->regs.ebp +#define FRAME_RETADDR_OFFSET 4 +#define FRAME_LINK_OFFSET 0 +#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.esp0) +#define STACK_TOP(tsk) ((tsk)->thread.esp0) +#else +#define UNW_FP(frame) ((void)(frame), 0) +#endif +#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) + +#define UNW_REGISTER_INFO \ + PTREGS_INFO(eax), \ + PTREGS_INFO(ecx), \ + PTREGS_INFO(edx), \ + PTREGS_INFO(ebx), \ + PTREGS_INFO(esp), \ + PTREGS_INFO(ebp), \ + PTREGS_INFO(esi), \ + PTREGS_INFO(edi), \ + PTREGS_INFO(eip) + +#define UNW_DEFAULT_RA(raItem, dataAlign) \ + ((raItem).where == Memory && \ + !((raItem).value * (dataAlign) + 4)) + +static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, + /*const*/ struct pt_regs *regs) +{ + if (user_mode_vm(regs)) + info->regs = *regs; + else { + memcpy(&info->regs, regs, offsetof(struct pt_regs, esp)); + info->regs.esp = (unsigned long)®s->esp; + info->regs.xss = __KERNEL_DS; + } +} + +static inline void arch_unw_init_blocked(struct unwind_frame_info *info) +{ + memset(&info->regs, 0, sizeof(info->regs)); + info->regs.eip = info->task->thread.eip; + info->regs.xcs = __KERNEL_CS; + __get_user(info->regs.ebp, (long *)info->task->thread.esp); + info->regs.esp = info->task->thread.esp; + info->regs.xss = __KERNEL_DS; + info->regs.xds = __USER_DS; + info->regs.xes = __USER_DS; +} + +extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *, + asmlinkage int (*callback)(struct unwind_frame_info *, + void *arg), + void *arg); + +static inline int arch_unw_user_mode(const struct unwind_frame_info *info) +{ +#if 0 /* This can only work when selector register and EFLAGS saves/restores + are properly annotated (and tracked in UNW_REGISTER_INFO). */ + return user_mode_vm(&info->regs); +#else + return info->regs.eip < PAGE_OFFSET + || (info->regs.eip >= __fix_to_virt(FIX_VDSO) + && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE) + || info->regs.esp < PAGE_OFFSET; +#endif +} + +#endif /* _STP_I386_UNWIND_H */ diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h new file mode 100644 index 00000000..8651cb9e --- /dev/null +++ b/runtime/unwind/unwind.h @@ -0,0 +1,142 @@ +/* -*- linux-c -*- + * + * dwarf unwinder header file + * Copyright (C) 2008 Red Hat Inc. + * Copyright (C) 2002-2006 Novell, Inc. + * + * 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. + */ + +#ifndef _STP_UNWIND_H_ +#define _STP_UNWIND_H_ + +#if defined (__x86_64__) +#include "x86_64.h" +#elif defined (__i386__) +#include "i386.h" +#else +#error "Unsupported dwarf unwind architecture" +#endif + +#define MAX_STACK_DEPTH 8 + +#define EXTRA_INFO(f) { \ + BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \ + % FIELD_SIZEOF(struct unwind_frame_info, f)) \ + + offsetof(struct unwind_frame_info, f) \ + / FIELD_SIZEOF(struct unwind_frame_info, f), \ + FIELD_SIZEOF(struct unwind_frame_info, f) \ + } +#define PTREGS_INFO(f) EXTRA_INFO(regs.f) + +static const struct { + unsigned offs:BITS_PER_LONG / 2; + unsigned width:BITS_PER_LONG / 2; +} reg_info[] = { + UNW_REGISTER_INFO +}; + +#undef PTREGS_INFO +#undef EXTRA_INFO + +#ifndef REG_INVALID +#define REG_INVALID(r) (reg_info[r].width == 0) +#endif + +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_CFA_offset_extended_sf 0x11 +#define DW_CFA_def_cfa_sf 0x12 +#define DW_CFA_def_cfa_offset_sf 0x13 +#define DW_CFA_val_offset 0x14 +#define DW_CFA_val_offset_sf 0x15 +#define DW_CFA_val_expression 0x16 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_GNU_window_save 0x2d +#define DW_CFA_GNU_args_size 0x2e +#define DW_CFA_GNU_negative_offset_extended 0x2f +#define DW_CFA_hi_user 0x3f + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_leb128 0x01 +#define DW_EH_PE_data2 0x02 +#define DW_EH_PE_data4 0x03 +#define DW_EH_PE_data8 0x04 +#define DW_EH_PE_FORM 0x07 /* mask */ +#define DW_EH_PE_signed 0x08 /* signed versions of above have this bit set */ + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 +#define DW_EH_PE_ADJUST 0x70 /* mask */ +#define DW_EH_PE_indirect 0x80 +#define DW_EH_PE_omit 0xff + +typedef unsigned long uleb128_t; +typedef signed long sleb128_t; + +static struct unwind_table { + unsigned long pc; /* text */ + unsigned long range; /* text_size */ + const void *address; /* unwind_data */ + unsigned long size; /* unwind_data_len */ + const unsigned char *header; /* unwind_header */ + unsigned long hdrsz; + struct unwind_table *link; + const char *name; /* module name */ +} root_table; + +struct unwind_item { + enum item_location { + Nowhere, + Memory, + Register, + Value + } where; + uleb128_t value; +}; + +struct unwind_state { + uleb128_t loc, org; + const u8 *cieStart, *cieEnd; + uleb128_t codeAlign; + sleb128_t dataAlign; + struct cfa { + uleb128_t reg, offs; + } cfa; + struct unwind_item regs[ARRAY_SIZE(reg_info)]; + unsigned stackDepth:8; + unsigned version:8; + const u8 *label; + const u8 *stack[MAX_STACK_DEPTH]; +}; + +static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; +static unsigned long read_pointer(const u8 **pLoc, + const void *end, + signed ptrType); +static const u32 bad_cie, not_fde; +static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *); +static signed fde_pointer_type(const u32 *cie); + +#endif /*_STP_UNWIND_H_*/ diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h new file mode 100644 index 00000000..eddf276d --- /dev/null +++ b/runtime/unwind/x86_64.h @@ -0,0 +1,101 @@ +#ifndef _STP_X86_64_UNWIND_H +#define _STP_X86_64_UNWIND_H + +/* + * Copyright (C) 2002-2006 Novell, Inc. + * Jan Beulich + * This code is released under version 2 of the GNU GPL. + */ + +#include +#include +#include + +/* these are simple for x86_64 */ +#define _stp_get_unaligned(ptr) (*(ptr)) +#define _stp_put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) + +struct unwind_frame_info +{ + struct pt_regs regs; + struct task_struct *task; + unsigned call_frame:1; +}; + +#define UNW_PC(frame) (frame)->regs.rip +#define UNW_SP(frame) (frame)->regs.rsp +#ifdef CONFIG_FRAME_POINTER +#define UNW_FP(frame) (frame)->regs.rbp +#define FRAME_RETADDR_OFFSET 8 +#define FRAME_LINK_OFFSET 0 +#define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1)) +#define STACK_TOP(tsk) ((tsk)->thread.rsp0) +#endif +/* Might need to account for the special exception and interrupt handling + stacks here, since normally + EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER, + but the construct is needed only for getting across the stack switch to + the interrupt stack - thus considering the IRQ stack itself is unnecessary, + and the overhead of comparing against all exception handling stacks seems + not desirable. */ +#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) + +#define UNW_REGISTER_INFO \ + PTREGS_INFO(rax), \ + PTREGS_INFO(rdx), \ + PTREGS_INFO(rcx), \ + PTREGS_INFO(rbx), \ + PTREGS_INFO(rsi), \ + PTREGS_INFO(rdi), \ + PTREGS_INFO(rbp), \ + PTREGS_INFO(rsp), \ + PTREGS_INFO(r8), \ + PTREGS_INFO(r9), \ + PTREGS_INFO(r10), \ + PTREGS_INFO(r11), \ + PTREGS_INFO(r12), \ + PTREGS_INFO(r13), \ + PTREGS_INFO(r14), \ + PTREGS_INFO(r15), \ + PTREGS_INFO(rip) + +#define UNW_DEFAULT_RA(raItem, dataAlign) \ + ((raItem).where == Memory && \ + !((raItem).value * (dataAlign) + 8)) + +static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, + /*const*/ struct pt_regs *regs) +{ + info->regs = *regs; +} + +static inline void arch_unw_init_blocked(struct unwind_frame_info *info) +{ + extern const char thread_return[]; + + memset(&info->regs, 0, sizeof(info->regs)); + info->regs.rip = (unsigned long)thread_return; + info->regs.cs = __KERNEL_CS; + __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp); + info->regs.rsp = info->task->thread.rsp; + info->regs.ss = __KERNEL_DS; +} + +extern int arch_unwind_init_running(struct unwind_frame_info *, + int (*callback)(struct unwind_frame_info *, + void *arg), + void *arg); + +static inline int arch_unw_user_mode(const struct unwind_frame_info *info) +{ +#if 0 /* This can only work when selector register saves/restores + are properly annotated (and tracked in UNW_REGISTER_INFO). */ + return user_mode(&info->regs); +#else + return (long)info->regs.rip >= 0 + || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END) + || (long)info->regs.rsp >= 0; +#endif +} + +#endif /* _STP_X86_64_UNWIND_H */ -- cgit From df3cfa3644c92994a8c21a1137d5970552aee30b Mon Sep 17 00:00:00 2001 From: eteo Date: Fri, 21 Mar 2008 14:35:25 +0000 Subject: 2008-03-21 Eugene Teo PR 5528 * tapset/conversions.stp (user_string_n, user_string_n2, user_string_n_warn, user_string_n_quoted, user_short, user_short_warn, user_int, user_int_warn, user_long, user_long_warn, user_char, user_char_warn): New user_* functions. * stapfuncs.5.in: Documented the new functions. * testsuite/systemtap.stress/conversions.stp: Test new functions. * testsuite/buildok/conversions.stp: Test new functions. * testsuite/buildok/conversions-embedded.stp: Test new functions. --- stapfuncs.5.in | 54 ++++++++++++ tapset/ChangeLog | 8 ++ tapset/conversions.stp | 130 ++++++++++++++++++++++++++++- testsuite/ChangeLog | 7 ++ testsuite/buildok/conversions-embedded.stp | 13 +++ testsuite/buildok/conversions.stp | 13 +++ testsuite/systemtap.stress/conversions.stp | 12 +++ 7 files changed, 236 insertions(+), 1 deletion(-) diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 85a00b37..9bca845d 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -92,6 +92,60 @@ fault, return instead the err_msg value. user_string_warn:string (addr:long) Copy a string from user space at given address. If the access would fault, signal a warning and return "". +.TP +user_string_quoted:string (addr:long) +Copy a string from user space at given address. Any ASCII characters +that are not printable are replaced by the corresponding escape +sequence in the returned string. +.TP +user_string_n:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. If the access +would fault, return "". +.TP +user_string_n2:string (addr:long, n:long, err_msg:string) +Copy a string of n bytes from user space at given address. If the access +would fault, return the err_msg value. +.TP +user_string_n_warn:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. If the access +would fault, signal a warning and return "". +.TP +user_string_n_quoted:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. Any ASCII +characters that are not printable are replaced by the corresponding escape +sequence in the returned string. If the access would fault, return "". +.TP +user_short:long (addr:long) +Copy a short from user space at given address. If the access would fault, +return 0. +.TP +user_short_warn:long (addr:long) +Copy a short from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_int:long (addr:long) +Copy an int from user space at given address. If the access would fault, +return 0. +.TP +user_int_warn:long (addr:long) +Copy an int from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_long:long (addr:long) +Copy a long from user space at given address. If the access would fault, +return 0. +.TP +user_long_warn:long (addr:long) +Copy a long from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_char:long (addr:long) +Copy a char from user space at given address. If the access would fault, +return 0. +.TP +user_char_warn:long (addr:long) +Copy a char from user space at given address. If the access would fault, +signal a warning and return 0. .SS STRING .TP strlen:long (str:string) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index da21a5ff..dae8b452 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,11 @@ +2008-03-21 Eugene Teo + + PR 5528 + * conversions.stp (user_string_n, user_string_n2, user_string_n_warn, + user_string_n_quoted, user_short, user_short_warn, user_int, + user_int_warn, user_long, user_long_warn, user_char, user_char_warn): + New user_* functions. + 2008-03-20 Frank Ch. Eigler PR 5956. diff --git a/tapset/conversions.stp b/tapset/conversions.stp index af993992..70725e9d 100644 --- a/tapset/conversions.stp +++ b/tapset/conversions.stp @@ -1,5 +1,5 @@ // conversions tapset -// Copyright (C) 2005-2007 Red Hat Inc. +// Copyright (C) 2005-2008 Red Hat Inc. // Copyright (C) 2007 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -108,3 +108,131 @@ function user_string_quoted:string (addr:long) %{ /* pure */ _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, MAXSTRINGLEN, 1, 1); %} + +function user_string_n:string (addr:long, n:long) { + return user_string_n2(addr, n, "") +} + +function user_string_n2:string (addr:long, n:long, err_msg:string) %{ /* pure */ + long len = THIS->n + 1; + len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; + if (_stp_strncpy_from_user(THIS->__retvalue, + (char __user *) (uintptr_t) THIS->addr, + len) < 0) + strlcpy(THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN); +%} + +function user_string_n_warn:string (addr:long, n:long) %{ /* pure */ + long len = THIS->n + 1; + long rc; + + len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; + rc = _stp_strncpy_from_user(THIS->__retvalue, + (char __user *) (uintptr_t) THIS->addr, len); + if (rc < 0) { + // NB: using error_buffer to get local space for the warning, but we're + // not aborting, so leave last_error alone. + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user string copy fault %ld at %p", rc, + (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); + } +%} + +function user_string_n_quoted:string (addr:long, n:long) %{ /* pure */ + long len = THIS->n + 1; + if (THIS->addr == 0) + strlcpy(THIS->__retvalue, "NULL", MAXSTRINGLEN); + else + /* XXX: stp_text_str uses sleepy __get_user() => unsafe ?! */ + _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, + len, 1, 1); +%} + +// When userspace data is not accessible, the following functions return 0 + +function user_short:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_short_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user short copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_int:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_int_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user int copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_long:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_long_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user long copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_char:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_char_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user char copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 16f7af57..14f96ecc 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-03-21 Eugene Teo + + PR 5528 + * systemtap.stress/conversions.stp: Test new user_* functions. + * buildok/conversions.stp: Test new user_* functions. + * buildok/conversions-embedded.stp: Test new user_* functions. + 2008-03-20 Frank Ch. Eigler PR 5956. diff --git a/testsuite/buildok/conversions-embedded.stp b/testsuite/buildok/conversions-embedded.stp index 7aa5a0b4..55f6cdb7 100755 --- a/testsuite/buildok/conversions-embedded.stp +++ b/testsuite/buildok/conversions-embedded.stp @@ -9,5 +9,18 @@ probe begin { print (user_string2 (0, "")) print (user_string_warn (0)) print (user_string_quoted (0)) + + print (user_string_n(0, 5)) + print (user_string_n2(0, 5, "foobar")) + print (user_string_n_warn(0, 0)) + print (user_string_n_quoted(0, 0)) + print (user_short(0)) + print (user_short_warn(0)) + print (user_int(0)) + print (user_int_warn(0)) + print (user_long(0)) + print (user_long_warn(0)) + print (user_char(0)) + print (user_char_warn(0)) } diff --git a/testsuite/buildok/conversions.stp b/testsuite/buildok/conversions.stp index e83bd968..5f151f1d 100755 --- a/testsuite/buildok/conversions.stp +++ b/testsuite/buildok/conversions.stp @@ -12,4 +12,17 @@ probe begin { print (user_string(2342)) print (user_string2(2342,"foobar")) print (user_string_warn(2342)) + + print (user_string_n(2342, 5)) + print (user_string_n2(2342, 5, "foobar")) + print (user_string_n_warn(2342, 5)) + print (user_string_n_quoted(2342, 5)) + print (user_short(2342)) + print (user_short_warn(2342)) + print (user_int(2342)) + print (user_int_warn(2342)) + print (user_long(2342)) + print (user_long_warn(2342)) + print (user_char(2342)) + print (user_char_warn(2342)) } diff --git a/testsuite/systemtap.stress/conversions.stp b/testsuite/systemtap.stress/conversions.stp index 07795a6d..34bd0c28 100644 --- a/testsuite/systemtap.stress/conversions.stp +++ b/testsuite/systemtap.stress/conversions.stp @@ -13,4 +13,16 @@ probe begin { print (user_string ($1)) } probe begin { print (user_string2 ($1,"")) } probe begin { print (user_string_warn ($1)) } probe begin { print (user_string_quoted ($1)) } +probe begin { print (user_string_n ($1, 5)) } +probe begin { print (user_string_n2 ($1, 5, "")) } +probe begin { print (user_string_n_warn ($1, 5)) } +probe begin { print (user_string_n_quoted ($1, 5)) } +probe begin { print (user_short ($1)) } +probe begin { print (user_short_warn ($1)) } +probe begin { print (user_int ($1)) } +probe begin { print (user_int_warn ($1)) } +probe begin { print (user_long ($1)) } +probe begin { print (user_long_warn ($1)) } +probe begin { print (user_char ($1)) } +probe begin { print (user_char_warn ($1)) } probe begin(1) { print ("\n") exit () } -- cgit From 44169f5dbcf16072c38a762f0c352601cb2133a7 Mon Sep 17 00:00:00 2001 From: fche Date: Sun, 23 Mar 2008 22:59:12 +0000 Subject: 2008-03-23 Frank Ch. Eigler PR 5980. * lib/systemtap.exp: Set default Snapshot: value from "stap -V" output. (cherry picked from commit 48a00e9396a77fbf1d9919c25eeeebc0081dfb4d) --- testsuite/ChangeLog | 6 ++++++ testsuite/lib/systemtap.exp | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 14f96ecc..628cb9a7 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-03-23 Frank Ch. Eigler + + PR 5980. + * lib/systemtap.exp: Set default Snapshot: value from "stap -V" + output. + 2008-03-21 Eugene Teo PR 5528 diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index baed0e41..d458e98f 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -58,8 +58,9 @@ proc get_system_info {} { } elseif [file exists $env(SRCDIR)/../SNAPSHOT] { set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT] } else { - set Snapshot "unknown" - } + regexp {version [^)]*} [exec stap -V 2>@ stdout] version + set Snapshot $version + } set Distro "Linux" if [file exists /etc/fedora-release] {set Distro [exec /bin/cat /etc/fedora-release]} if [file exists /etc/redhat-release] {set Distro [exec /bin/cat /etc/redhat-release]} -- cgit From 874381d3fc30dddd9f8584f3f6a9a36a1a4ad9df Mon Sep 17 00:00:00 2001 From: fche Date: Sun, 23 Mar 2008 23:01:43 +0000 Subject: 2008-03-23 Frank Ch. Eigler * lib/stap_run.exp (stap_run): Ignore missing debuginfo warnings. Try harder to kill stap child in case of timeouts and errors. (cherry picked from commit ef859360e89d32801e37ddecf59ceee20a049391) --- testsuite/ChangeLog | 5 +++++ testsuite/lib/stap_run.exp | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 628cb9a7..a54e80bd 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-03-23 Frank Ch. Eigler + + * lib/stap_run.exp (stap_run): Ignore missing debuginfo warnings. + Try harder to kill stap child in case of timeouts and errors. + 2008-03-23 Frank Ch. Eigler PR 5980. diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index c2b4e74d..42efa4f8 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -34,6 +34,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } expect { -timeout 180 -re {^Warning: using '-m' disables cache support.\r\n} {exp_continue} + -re {^WARNING: cannot find module [^\r]*DWARF[^\r]*\r\n} {exp_continue} -re {^Pass\ ([1234]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms\.\r\n} {set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"; exp_continue} -re {^Pass\ ([34]): using cached [^\r]+\r\n} @@ -73,15 +74,22 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } set skipped_probes $expect_out(2,string)} } } - timeout { fail "$TEST_NAME shutdown (timeout)" } + timeout { + fail "$TEST_NAME shutdown (timeout)" + exec kill -INT -[exp_pid] + } eof { fail "$TEST_NAME shutdown (eof)" } } } -re "semantic error:" { fail "$TEST_NAME compilation" } - timeout { fail "$TEST_NAME startup (timeout)" - exec kill -INT [exp_pid] } + timeout { + fail "$TEST_NAME startup (timeout)" + exec kill -INT -[exp_pid] + } eof { fail "$TEST_NAME startup (eof)" } } + # again for good measure + exec kill -INT -[exp_pid] catch close wait } -- cgit From b56639bb84656464efbf88912f68c36e7f099d49 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Tue, 25 Mar 2008 12:26:46 -0400 Subject: Cleanup. --- .gitignore | 1 + runtime/ChangeLog | 5 +++ runtime/stack-x86_64.c | 7 ++-- runtime/unwind.c | 107 ++++++++++++++++++++++++++---------------------- runtime/unwind/i386.h | 11 +++++ runtime/unwind/x86_64.h | 12 ++++++ 6 files changed, 91 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 1c02452b..90261357 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ CVS .metadata .project .settings +*.o diff --git a/runtime/ChangeLog b/runtime/ChangeLog index b52ddf7b..bea8b3a3 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,8 @@ +2008-03-25 Martin Hunt + + * unwind.c (unwind): Return a positive number to indicate + that unwinding is done. + 2008-03-17 Eugene Teo PR 5947 diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 3ba99201..e2eb4aa2 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -30,16 +30,15 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels) struct unwind_frame_info info; arch_unw_init_frame_info(&info, regs); - /* we haven't actually executed the instruction at the IP yet. */ - UNW_PC(&info) -= 1; - while (!arch_unw_user_mode(&info)) { int ret = unwind(&info); - dbug_unwind(1, "ret=%d PC=%lx\n", ret, UNW_PC(&info)); + dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); if (ret < 0) { _stp_stack_print_fallback(UNW_SP(&info), verbose); break; } + if (ret) + break; _stp_func_print(UNW_PC(&info), verbose, 1); } } diff --git a/runtime/unwind.c b/runtime/unwind.c index 9a5d61e8..b6c9fd75 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -1,12 +1,16 @@ -/* +/* -*- linux-c -*- + * kernel stack unwinding + * Copyright (C) 2008 Red Hat Inc. + * + * Based on old kernel code that is * Copyright (C) 2002-2006 Novell, Inc. * Jan Beulich + * * This code is released under version 2 of the GNU GPL. * - * A simple API for unwinding kernel stacks. This is used for - * debugging and error reporting purposes. The kernel doesn't need - * full-blown stack unwinding with all the bells and whistles, so there - * is not much point in implementing the full Dwarf2 unwind API. + * This code currently does stack unwinding in the + * kernel and modules. It will need some extension to handle + * userspace unwinding. */ #include "unwind/unwind.h" @@ -231,8 +235,8 @@ static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m) /* CIE_pointer must be a proper offset */ if ((fde[1] & (sizeof(*fde) - 1)) || fde[1] > (unsigned long)(fde + 1) - (unsigned long)m->unwind_data) { dbug_unwind(1, "fde[1]=%lx fde+1=%lx, unwind_data=%lx %lx\n", - (unsigned long)fde[1], (unsigned long)(fde + 1), - (unsigned long)m->unwind_data, (unsigned long)(fde + 1) - (unsigned long)m->unwind_data); + (unsigned long)fde[1], (unsigned long)(fde + 1), + (unsigned long)m->unwind_data, (unsigned long)(fde + 1) - (unsigned long)m->unwind_data); return NULL; /* this is not a valid FDE */ } @@ -400,6 +404,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s } ptr; int result = 1; + dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc); if (start != state->cieStart) { state->loc = state->org; result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state); @@ -542,6 +547,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s dbug_unwind(1, "case 3\n"); break; } + dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc); if (ptr.p8 > end) result = 0; if (result && targetLoc != 0 && targetLoc < state->loc) @@ -560,9 +566,6 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m) u32 *fde = NULL; unsigned num, tableSize, t2; - /* TOTO: only really need to test hdr == NULL */ - /* The rest should be validated at load time */ - if (hdr == NULL || hdr[0] != 1) return NULL; @@ -614,12 +617,13 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m) if (num == 1 && (startLoc = read_pointer(&ptr, ptr + tableSize, hdr[3])) != 0 && pc >= startLoc) fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]); - dbug_unwind(1, "returning %lx", fde); + dbug_unwind(1, "returning fde=%lx startLoc=%lx", fde, startLoc); return fde; } /* Unwind to previous to frame. Returns 0 if successful, negative - * number in case of an error. */ + * number in case of an error. A positive return means unwinding is finished; */ +/* don't try to fallback to dumping addresses on the stack. */ int unwind(struct unwind_frame_info *frame) { #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) @@ -646,32 +650,36 @@ int unwind(struct unwind_frame_info *frame) if (unlikely(m->unwind_data_len == 0 || m->unwind_data_len & (sizeof(*fde) - 1))) { dbug_unwind(1, "Module %s: unwind_data_len=%d", m->name, m->unwind_data_len); - goto done; + goto err; } fde = _stp_search_unwind_hdr(pc, m); dbug_unwind(1, "%s: fde=%lx\n", m->name, fde); + /* found the fde, now set startLoc and endLoc */ if (fde != NULL) { cie = cie_for_fde(fde, m); ptr = (const u8 *)(fde + 2); - if (cie != NULL - && cie != &bad_cie - && cie != ¬_fde - && (ptrType = fde_pointer_type(cie)) >= 0 - && read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType) == startLoc) { + if (likely(cie != NULL && cie != &bad_cie && cie != ¬_fde)) { + ptrType = fde_pointer_type(cie); + startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); if (!(ptrType & DW_EH_PE_indirect)) ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); - if (pc >= endLoc) - fde = NULL; - } else + if (pc > endLoc) { + dbug_unwind(1, "pc (%lx) > endLoc(%x)\n", pc, endLoc); + /* finished? */ + goto done; + } + } else { + dbug_unwind(1, "fde found in header, but cie is bad!\n"); fde = NULL; + } } if (fde == NULL) { for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { - // dbug_unwind(1,"fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize); + dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize); cie = cie_for_fde(fde, m); if (cie == &bad_cie) { cie = NULL; @@ -682,13 +690,13 @@ int unwind(struct unwind_frame_info *frame) ptr = (const u8 *)(fde + 2); startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); - // dbug_unwind(1,"startLoc=%p\n",(u64)startLoc); + dbug_unwind(3, "startLoc=%p\n", (u64)startLoc); if (!startLoc) continue; if (!(ptrType & DW_EH_PE_indirect)) ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); - // dbug_unwind(1,"endLoc=%p\n",(u64)endLoc); + dbug_unwind(3, "endLoc=%p\n", (u64)endLoc); if (pc >= startLoc && pc < endLoc) break; } @@ -696,7 +704,7 @@ int unwind(struct unwind_frame_info *frame) dbug_unwind(1, "cie=%lx fde=%lx startLoc=%lx endLoc=%lx\n", cie, fde, startLoc, endLoc); if (cie == NULL || fde == NULL) - goto done; + goto err; /* found the CIE and FDE */ @@ -707,7 +715,7 @@ int unwind(struct unwind_frame_info *frame) frame->call_frame = 1; if ((state.version = *ptr) != 1) { dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version); - goto done; /* unsupported version */ + goto err; /* unsupported version */ } if (*++ptr) { /* check if augmentation size is first (and thus present) */ @@ -731,7 +739,7 @@ int unwind(struct unwind_frame_info *frame) } if (ptr >= end || *ptr) { dbug_unwind(1, "Problem parsing the augmentation string.\n"); - goto done; + goto err; } } ++ptr; @@ -741,7 +749,7 @@ int unwind(struct unwind_frame_info *frame) /* get data aligment factor */ state.dataAlign = get_sleb128(&ptr, end); if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) - goto done;; + goto err;; retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); @@ -753,7 +761,7 @@ int unwind(struct unwind_frame_info *frame) if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info) || REG_INVALID(retAddrReg) || reg_info[retAddrReg].width != sizeof(unsigned long)) - goto done; + goto err; state.cieStart = ptr; ptr = state.cieEnd; @@ -764,7 +772,7 @@ int unwind(struct unwind_frame_info *frame) if (((const char *)(cie + 2))[1] == 'z') { uleb128_t augSize = get_uleb128(&ptr, end); if ((ptr += augSize) > end) - goto done; + goto err; } state.org = startLoc; @@ -774,7 +782,7 @@ int unwind(struct unwind_frame_info *frame) || state.loc > endLoc || state.regs[retAddrReg].where == Nowhere || state.cfa.reg >= ARRAY_SIZE(reg_info) || reg_info[state.cfa.reg].width != sizeof(unsigned long) || state.cfa.offs % sizeof(unsigned long)) - goto done; + goto err; /* update frame */ dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde); @@ -801,10 +809,10 @@ int unwind(struct unwind_frame_info *frame) if (REG_INVALID(i)) { if (state.regs[i].where == Nowhere) continue; - dbug_unwind(1, "REG_INVALID %d\n", i); - goto done; + dbug_unwind(2, "REG_INVALID %d\n", i); + goto err; } - dbug_unwind(1, "register %d. where=%d\n", i, state.regs[i].where); + dbug_unwind(2, "register %d. where=%d\n", i, state.regs[i].where); switch (state.regs[i].where) { default: break; @@ -812,8 +820,8 @@ int unwind(struct unwind_frame_info *frame) if (state.regs[i].value >= ARRAY_SIZE(reg_info) || REG_INVALID(state.regs[i].value) || reg_info[i].width > reg_info[state.regs[i].value].width) { - dbug_unwind(1, "case Register bad\n"); - goto done; + dbug_unwind(2, "case Register bad\n"); + goto err; } switch (reg_info[state.regs[i].value].width) { #define CASE(n) \ @@ -824,17 +832,17 @@ int unwind(struct unwind_frame_info *frame) CASES; #undef CASE default: - dbug_unwind(1, "default\n"); - goto done; + dbug_unwind(2, "default\n"); + goto err; } break; } } for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { - dbug_unwind(1, "register %d. invalid=%d\n", i, REG_INVALID(i)); + dbug_unwind(2, "register %d. invalid=%d\n", i, REG_INVALID(i)); if (REG_INVALID(i)) continue; - dbug_unwind(1, "register %d. where=%d\n", i, state.regs[i].where); + dbug_unwind(2, "register %d. where=%d\n", i, state.regs[i].where); switch (state.regs[i].where) { case Nowhere: if (reg_info[i].width != sizeof(UNW_SP(frame)) @@ -851,20 +859,20 @@ int unwind(struct unwind_frame_info *frame) CASES; #undef CASE default: - dbug_unwind(1, "default\n"); - goto done; + dbug_unwind(2, "default\n"); + goto err; } break; case Value: if (reg_info[i].width != sizeof(unsigned long)) { - dbug_unwind(1, "Value\n"); - goto done; + dbug_unwind(2, "Value\n"); + goto err; } FRAME_REG(i, unsigned long) = cfa + state.regs[i].value * state.dataAlign; break; case Memory:{ unsigned long addr = cfa + state.regs[i].value * state.dataAlign; - dbug_unwind(1, "addr=%lx width=%d\n", addr, reg_info[i].width); + dbug_unwind(2, "addr=%lx width=%d\n", addr, reg_info[i].width); switch (reg_info[i].width) { #define CASE(n) case sizeof(u##n): \ if (unlikely(__stp_get_user(FRAME_REG(i, u##n), (u##n *)addr))) \ @@ -874,8 +882,8 @@ int unwind(struct unwind_frame_info *frame) CASES; #undef CASE default: - dbug_unwind(1, "default\n"); - goto done; + dbug_unwind(2, "default\n"); + goto err; } } break; @@ -887,9 +895,12 @@ int unwind(struct unwind_frame_info *frame) copy_failed: dbug_unwind(1, "_stp_get_user failed to access memory\n"); -done: +err: read_unlock(&m->lock); return -EIO; +done: + read_unlock(&m->lock); + return 1; #undef CASES #undef FRAME_REG } diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index de68c67b..1a6b678b 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -1,3 +1,14 @@ +/* -*- linux-c -*- + * + * 32-bit x86 dwarf unwinder header file + * Copyright (C) 2008 Red Hat Inc. + * Copyright (C) 2002-2006 Novell, Inc. + * + * 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. + */ #ifndef _STP_I386_UNWIND_H #define _STP_I386_UNWIND_H diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index eddf276d..3c4a97be 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -1,3 +1,14 @@ +/* -*- linux-c -*- + * + * x86_64 dwarf unwinder header file + * Copyright (C) 2008 Red Hat Inc. + * Copyright (C) 2002-2006 Novell, Inc. + * + * 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. + */ #ifndef _STP_X86_64_UNWIND_H #define _STP_X86_64_UNWIND_H @@ -67,6 +78,7 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs) { info->regs = *regs; + info->call_frame = 1; } static inline void arch_unw_init_blocked(struct unwind_frame_info *info) -- cgit From a8bfd6f19b6fd8b8091b9123e38c77abdebc2fb9 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Tue, 25 Mar 2008 13:44:37 -0400 Subject: 32-bit fixes --- runtime/transport/ChangeLog | 5 +++++ runtime/transport/symbols.c | 10 +++++----- runtime/transport/transport_msgs.h | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index c3837f86..9fea0dd4 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,8 @@ +2008-03-25 Martin Hunt + 32-bit systems can't do 64-bit get_user(), so + * symbols.c (_stp_do_unwind_data): Change unwind_len to a u32. + * transport_msgs.h (struct _stp_msg_unwind): Ditto. + 2008-02-27 Martin Hunt * symbols.c: Use rwlocks. Use new dbug macros. Handle diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 6406d6ad..a81e594f 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -205,7 +205,7 @@ static int _stp_init_kernel_symbols(void) static void _stp_do_unwind_data(const char __user *buf, size_t count) { - u64 unwind_len; + u32 unwind_len; unsigned long flags; char name[STP_MODULE_NAME_LEN]; int i; @@ -213,7 +213,7 @@ static void _stp_do_unwind_data(const char __user *buf, size_t count) dbug_unwind(1, "got unwind data, count=%d\n", count); - if (count < STP_MODULE_NAME_LEN + sizeof(u64)) { + if (count < STP_MODULE_NAME_LEN + sizeof(unwind_len)) { dbug_unwind(1, "unwind message too short\n"); return; } @@ -230,12 +230,12 @@ static void _stp_do_unwind_data(const char __user *buf, size_t count) count -= STP_MODULE_NAME_LEN; buf += STP_MODULE_NAME_LEN; - if (get_user(unwind_len, (u64 __user *)buf)) { + if (get_user(unwind_len, (u32 __user *)buf)) { errk("userspace copy failed\n"); return; } - count -= sizeof(u64); - buf += sizeof(u64); + count -= sizeof(unwind_len); + buf += sizeof(unwind_len); if (count != unwind_len) { dbug_unwind(1, "count=%d unwind_len=%d\n", (int)count, (int)unwind_len); return; diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 0e65b63a..5f385565 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -72,7 +72,7 @@ struct _stp_msg_unwind /* the module name, or "*" for all */ char name[STP_MODULE_NAME_LEN]; /* length of unwind data */ - uint64_t unwind_len; + uint32_t unwind_len; /* data ...*/ }; -- cgit From 5280c736a9466cd97f56ebb508be2371aacb1d53 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Tue, 25 Mar 2008 14:01:36 -0400 Subject: control.c (_stp_ctl_write_dbug): Insert missing break. --- runtime/transport/ChangeLog | 3 +++ runtime/transport/control.c | 1 + 2 files changed, 4 insertions(+) diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 9fea0dd4..2db40a12 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,4 +1,7 @@ 2008-03-25 Martin Hunt + + * control.c (_stp_ctl_write_dbug): Insert missing break. + 32-bit systems can't do 64-bit get_user(), so * symbols.c (_stp_do_unwind_data): Change unwind_len to a u32. * transport_msgs.h (struct _stp_msg_unwind): Ditto. diff --git a/runtime/transport/control.c b/runtime/transport/control.c index ed7725fa..92334b9c 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -106,6 +106,7 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_UNWIND: snprintf(buf, sizeof(buf), "%s", (char *)data); _dbug("sending STP_UNWIND %s [len=%d]\n", buf, len); + break; default: _dbug("ERROR: unknown message type: %d\n", type); break; -- cgit From fd2ef8221625866219d6fc8e99ac36520ac6017b Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Wed, 26 Mar 2008 10:06:19 -0400 Subject: i386 fixes. --- runtime/ChangeLog | 7 +++++ runtime/stack-i386.c | 71 +++++++++++++++++++++++++++++++++---------------- runtime/unwind.c | 2 +- runtime/unwind/i386.h | 12 +-------- runtime/unwind/x86_64.h | 5 ---- 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index bea8b3a3..e56fa729 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,10 @@ +2008-03-26 Martin Hunt + Fixes to get i386 working. + * unwind.c (unwind): Fix types in debug print. + * stack-i386.c (_stp_stack_print_fallback): New function. + (__stp_stack_print): Call _stp_stack_print_fallback() if unwinder + appears to fail. + 2008-03-25 Martin Hunt * unwind.c (unwind): Return a positive number to indicate diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index b46ff06b..a86f94be 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -8,40 +8,65 @@ * later version. */ -static inline int _stp_valid_stack_ptr(unsigned long context, unsigned long p) +static int _stp_valid_stack_ptr(unsigned long context, unsigned long p) { return p > context && p < context + THREAD_SIZE - 3; } +/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ +static void _stp_stack_print_fallback(unsigned long context, unsigned long stack, int verbose) +{ + unsigned long addr; + while (_stp_valid_stack_ptr(context, stack)) { + if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) { + /* cannot access stack. give up. */ + return; + } + _stp_func_print(addr, verbose, 0); + stack++; + } +} + static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) { unsigned long *stack = (unsigned long *)®_SP(regs); unsigned long context = (unsigned long)stack & ~(THREAD_SIZE - 1); - unsigned long addr; #ifdef CONFIG_FRAME_POINTER - { - #ifdef STAPCONF_X86_UNIREGS - unsigned long ebp = regs->bp; - #else - unsigned long ebp = regs->ebp; - #endif - - while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { - addr = *(unsigned long *)(ebp + 4); - if (verbose) { - _stp_print_char(' '); - _stp_symbol_print (addr); - _stp_print_char('\n'); - } else - _stp_printf ("0x%08lx ", addr); - ebp = *(unsigned long *)ebp; - } + /* FIXME: need to use _stp_func_print() and safe copy */ + unsigned long addr; + +#ifdef STAPCONF_X86_UNIREGS + unsigned long ebp = regs->bp; +#else + unsigned long ebp = regs->ebp; +#endif /* STAPCONF_X86_UNIREGS */ + + while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { + addr = *(unsigned long *)(ebp + 4); + if (verbose) { + _stp_print_char(' '); + _stp_symbol_print (addr); + _stp_print_char('\n'); + } else + _stp_printf ("0x%08lx ", addr); + ebp = *(unsigned long *)ebp; } #else - while (_stp_valid_stack_ptr(context, (unsigned long)stack)) { - addr = *stack++; - _stp_func_print(addr, verbose, 1); + struct unwind_frame_info info; + arch_unw_init_frame_info(&info, regs); + while (!arch_unw_user_mode(&info)) { + int ret = unwind(&info); + dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); + if (ret < 0) { + _stp_stack_print_fallback(context, UNW_SP(&info), verbose); + break; + } + if (ret) + break; + _stp_func_print(UNW_PC(&info), verbose, 1); } -#endif +// _stp_printf("***********************\n"); +// _stp_stack_print_fallback(context, (unsigned long)stack, verbose); +#endif /* CONFIG_FRAME_POINTER */ } diff --git a/runtime/unwind.c b/runtime/unwind.c index b6c9fd75..483c9345 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -804,7 +804,7 @@ int unwind(struct unwind_frame_info *frame) #else # define CASES CASE(8); CASE(16); CASE(32); CASE(64) #endif - dbug_unwind(1, "cie=%p fde=%p\n", (u64)cie, (u64)fde); + dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde); for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { if (REG_INVALID(i)) { if (state.regs[i].where == Nowhere) diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index 1a6b678b..cb2efab7 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -12,13 +12,6 @@ #ifndef _STP_I386_UNWIND_H #define _STP_I386_UNWIND_H -/* - * Copyright (C) 2002-2006 Novell, Inc. - * Jan Beulich - * This code is released under version 2 of the GNU GPL. - */ - - #include #include #include @@ -73,6 +66,7 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, info->regs.esp = (unsigned long)®s->esp; info->regs.xss = __KERNEL_DS; } + info->call_frame = 1; } static inline void arch_unw_init_blocked(struct unwind_frame_info *info) @@ -87,10 +81,6 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) info->regs.xes = __USER_DS; } -extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *, - asmlinkage int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); static inline int arch_unw_user_mode(const struct unwind_frame_info *info) { diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index 3c4a97be..6e6e521f 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -93,11 +93,6 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) info->regs.ss = __KERNEL_DS; } -extern int arch_unwind_init_running(struct unwind_frame_info *, - int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); - static inline int arch_unw_user_mode(const struct unwind_frame_info *info) { #if 0 /* This can only work when selector register saves/restores -- cgit From 614ead2b7dd8ac70cd89d018b09a397be7ade371 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Fri, 28 Mar 2008 16:20:02 -0400 Subject: kretprobe trampoline fixes Recognize when a kretprobe trampoline was hit and continue with inexact stack dump. Also some testsuite changes. --- runtime/stack-i386.c | 22 +++--- runtime/stack-x86_64.c | 17 +++-- runtime/stack.c | 22 +++--- runtime/sym.h | 1 + runtime/transport/symbols.c | 2 + runtime/unwind.c | 86 ++++++++++++++++++--- testsuite/systemtap.context/backtrace.stp | 27 +++---- testsuite/systemtap.context/backtrace.tcl | 123 +++++++++++++++++------------- 8 files changed, 194 insertions(+), 106 deletions(-) diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index a86f94be..d7c2c201 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -43,7 +43,10 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) #endif /* STAPCONF_X86_UNIREGS */ while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { - addr = *(unsigned long *)(ebp + 4); + if (unlikely(__stp_get_user(addr, (unsigned long *)(ebp + 4)))) { + /* cannot access stack. give up. */ + return; + } if (verbose) { _stp_print_char(' '); _stp_symbol_print (addr); @@ -55,18 +58,19 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) #else struct unwind_frame_info info; arch_unw_init_frame_info(&info, regs); + while (!arch_unw_user_mode(&info)) { int ret = unwind(&info); dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); - if (ret < 0) { - _stp_stack_print_fallback(context, UNW_SP(&info), verbose); - break; + if (ret == 0) { + _stp_func_print(UNW_PC(&info), verbose, 1); + continue; } - if (ret) - break; - _stp_func_print(UNW_PC(&info), verbose, 1); + /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */ + /* FIXME: is there a way to unwind across kretprobe trampolines? */ + if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline)) + _stp_stack_print_fallback(UNW_SP(&info), verbose); + break; } -// _stp_printf("***********************\n"); -// _stp_stack_print_fallback(context, (unsigned long)stack, verbose); #endif /* CONFIG_FRAME_POINTER */ } diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index e2eb4aa2..846653be 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -8,13 +8,12 @@ * later version. */ -// todo: don't use unwinder for kernel if CONFIG_FRAME +// todo: don't use unwinder for kernel if CONFIG_FRAME /* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ static void _stp_stack_print_fallback(unsigned long stack, int verbose) { unsigned long addr; - while (stack & (THREAD_SIZE - 1)) { if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) { /* cannot access stack. give up. */ @@ -33,12 +32,14 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels) while (!arch_unw_user_mode(&info)) { int ret = unwind(&info); dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); - if (ret < 0) { - _stp_stack_print_fallback(UNW_SP(&info), verbose); - break; + if (ret == 0) { + _stp_func_print(UNW_PC(&info), verbose, 1); + continue; } - if (ret) - break; - _stp_func_print(UNW_PC(&info), verbose, 1); + /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */ + /* FIXME: is there a way to unwind across kretprobe trampolines? */ + if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline)) + _stp_stack_print_fallback(UNW_SP(&info), verbose); + break; } } diff --git a/runtime/stack.c b/runtime/stack.c index e338f587..eefdf715 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -58,12 +58,15 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan _stp_symbol_print((unsigned long)_stp_ret_addr_r(pi)); } else { _stp_print_char(' '); - _stp_symbol_print (REG_IP(regs)); + _stp_symbol_print(REG_IP(regs)); } _stp_print_char('\n'); - } else - _stp_printf ("%p ", (int64_t)REG_IP(regs)); - __stp_stack_print (regs, verbose, 0); + } else if (pi) + _stp_printf("%p %p ", (int64_t) _stp_ret_addr_r(pi), (int64_t) REG_IP(regs)); + else + _stp_printf("%p ", (int64_t) REG_IP(regs)); + + __stp_stack_print(regs, verbose, 0); } /** Writes stack backtrace to a string @@ -72,7 +75,7 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan * @param regs A pointer to the struct pt_regs. * @returns void */ -void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi) +void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi) { /* To get a string, we use a simple trick. First flush the print buffer, */ /* then call _stp_stack_print, then copy the result into the output string */ @@ -84,19 +87,18 @@ void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose, pb->len = 0; } - /** Prints the user stack backtrace * @param str string * @returns Same string as was input with trace info appended, * @note Currently limited to a depth of two. Works from jprobes and kprobes. */ #if 0 -void _stp_ustack_print (char *str) +void _stp_ustack_print(char *str) { - struct pt_regs *nregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1; - _stp_printf ("%p : [user]\n", (int64_t)REG_IP(nregs)); + struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1; + _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs)); if (REG_SP(nregs)) - _stp_printf ("%p : [user]\n", (int64_t)(*(unsigned long *)REG_SP(nregs))); + _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs))); } #endif /* 0 */ diff --git a/runtime/sym.h b/runtime/sym.h index 631a5bbf..0bb64c13 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -84,6 +84,7 @@ struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES]; /* the number of modules in the arrays */ int _stp_num_modules = 0; +static unsigned long _stp_kretprobe_trampoline = 0; unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset); static struct _stp_module *_stp_get_unwind_info (unsigned long addr); diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index a81e594f..83a3a635 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -200,6 +200,8 @@ static int _stp_init_kernel_symbols(void) _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text; _stp_modules_by_addr[0] = _stp_modules[0]; + + _stp_kretprobe_trampoline = _stp_kallsyms_lookup_name("kretprobe_trampoline"); return 0; } diff --git a/runtime/unwind.c b/runtime/unwind.c index 483c9345..e8cba72e 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -321,7 +321,7 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy return 0; } if ((ptrType & DW_EH_PE_indirect) - && __stp_get_user(value, (unsigned long *)value)) + && __stp_get_user(value, (unsigned long *)value)) return 0; *pLoc = ptr.p8; @@ -621,15 +621,62 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m) return fde; } +#ifdef DEBUG_UNWIND +static const char *_stp_enc_hi_name[] = { + "", + "DW_EH_PE_pcrel", + "DW_EH_PE_textrel", + "DW_EH_PE_datarel", + "DW_EH_PE_funcrel", + "DW_EH_PE_aligned" +}; +static const char *_stp_enc_lo_name[] = { + "DW_EH_PE_absptr", + "DW_EH_PE_uleb128", + "DW_EH_PE_udata2", + "DW_EH_PE_udata4", + "DW_EH_PE_udata8", + "DW_EH_PE_sleb128", + "DW_EH_PE_sdata2", + "DW_EH_PE_sdata4", + "DW_EH_PE_sdata8" +}; +char *_stp_eh_enc_name(signed type) +{ + static char buf[64]; + int hi, low; + if (type == DW_EH_PE_omit) + return "DW_EH_PE_omit"; + + hi = (type & DW_EH_PE_ADJUST) >> 4; + low = type & DW_EH_PE_FORM; + if (hi > 5 || low > 4 || (low == 0 && (type & DW_EH_PE_signed))) { + sprintf(buf, "ERROR:encoding=0x%x", type); + return buf; + } + + buf[0] = 0; + if (type & DW_EH_PE_indirect) + strlcpy(buf, "DW_EH_PE_indirect|", sizeof(buf)); + if (hi) + strlcat(buf, _stp_enc_hi_name[hi], sizeof(buf)); + + if (type & DW_EH_PE_signed) + low += 4; + strlcat(buf, _stp_enc_lo_name[low], sizeof(buf)); + return buf; +} +#endif /* DEBUG_UNWIND */ + /* Unwind to previous to frame. Returns 0 if successful, negative - * number in case of an error. A positive return means unwinding is finished; */ -/* don't try to fallback to dumping addresses on the stack. */ + * number in case of an error. A positive return means unwinding is finished; + * don't try to fallback to dumping addresses on the stack. */ int unwind(struct unwind_frame_info *frame) { #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) const u32 *fde, *cie = NULL; const u8 *ptr = NULL, *end = NULL; - unsigned long pc = UNW_PC(frame) - frame->call_frame; + unsigned long pc = UNW_PC(frame); unsigned long tableSize, startLoc = 0, endLoc = 0, cfa; unsigned i; signed ptrType = -1; @@ -637,6 +684,15 @@ int unwind(struct unwind_frame_info *frame) struct _stp_module *m; struct unwind_state state; + if (pc != _stp_kretprobe_trampoline) + pc -= frame->call_frame; + else { + unsigned long a1, a2, *addr = (unsigned long *)UNW_SP(frame); + __stp_get_user(a1, addr); + __stp_get_user(a2, addr+1); + dbug_unwind(1, "TRAMPOLINE: SP=%lx *SP=%lx *(SP+1)=%lx\n", UNW_SP(frame), a1, a2); + return -EINVAL; + } dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame)); if (UNW_PC(frame) == 0) @@ -659,16 +715,16 @@ int unwind(struct unwind_frame_info *frame) /* found the fde, now set startLoc and endLoc */ if (fde != NULL) { cie = cie_for_fde(fde, m); - ptr = (const u8 *)(fde + 2); if (likely(cie != NULL && cie != &bad_cie && cie != ¬_fde)) { + ptr = (const u8 *)(fde + 2); ptrType = fde_pointer_type(cie); startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); + dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType)); if (!(ptrType & DW_EH_PE_indirect)) ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); if (pc > endLoc) { - dbug_unwind(1, "pc (%lx) > endLoc(%x)\n", pc, endLoc); - /* finished? */ + dbug_unwind(1, "pc (%lx) > endLoc(%lx)\n", pc, endLoc); goto done; } } else { @@ -676,6 +732,8 @@ int unwind(struct unwind_frame_info *frame) fde = NULL; } } + + /* did not a good fde find with binary search, so do slow linear search */ if (fde == NULL) { for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { @@ -690,13 +748,13 @@ int unwind(struct unwind_frame_info *frame) ptr = (const u8 *)(fde + 2); startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); - dbug_unwind(3, "startLoc=%p\n", (u64)startLoc); + dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType)); if (!startLoc) continue; if (!(ptrType & DW_EH_PE_indirect)) ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed; endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); - dbug_unwind(3, "endLoc=%p\n", (u64)endLoc); + dbug_unwind(3, "endLoc=%lx\n", endLoc); if (pc >= startLoc && pc < endLoc) break; } @@ -729,6 +787,7 @@ int unwind(struct unwind_frame_info *frame) case 'R': continue; case 'S': + dbug_unwind(1, "This is a signal frame\n"); frame->call_frame = 0; continue; default: @@ -785,7 +844,6 @@ int unwind(struct unwind_frame_info *frame) goto err; /* update frame */ - dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde); #ifndef CONFIG_AS_CFI_SIGNAL_FRAME if (frame->call_frame && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign)) frame->call_frame = 0; @@ -793,11 +851,11 @@ int unwind(struct unwind_frame_info *frame) cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; startLoc = min((unsigned long)UNW_SP(frame), cfa); endLoc = max((unsigned long)UNW_SP(frame), cfa); - dbug_unwind(1, "cfa=%lx SP startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc); + dbug_unwind(1, "cfa=%lx startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc); if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) { startLoc = min(STACK_LIMIT(cfa), cfa); endLoc = max(STACK_LIMIT(cfa), cfa); - dbug_unwind(1, "SP startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc); + dbug_unwind(1, "cfa startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc); } #ifndef CONFIG_64BIT # define CASES CASE(8); CASE(16); CASE(32) @@ -898,7 +956,11 @@ copy_failed: err: read_unlock(&m->lock); return -EIO; + done: + /* PC was in a range convered by a module but no unwind info */ + /* found for the specific PC. This seems to happen only for kretprobe */ + /* trampolines and at the end of interrupt backtraces. */ read_unlock(&m->lock); return 1; #undef CASES diff --git a/testsuite/systemtap.context/backtrace.stp b/testsuite/systemtap.context/backtrace.stp index c14d071c..ddd7d00a 100644 --- a/testsuite/systemtap.context/backtrace.stp +++ b/testsuite/systemtap.context/backtrace.stp @@ -1,10 +1,9 @@ -function print_all_trace_info(point:string) { +function print_all_trace_info(point) { printf("backtrace from %s:\n", pp()) print_backtrace() - print("--------\n") + printf("--- %s ---\n", point) bt = backtrace() - printf("the %s stack is %s\n", point, bt) - printf("--<%s>--\n", point) + printf("the stack is %s\n", bt) print_stack(bt); print("--------\n") } @@ -18,18 +17,20 @@ probe end { } global flag = 0 -probe module("systemtap_test_module2").function("yyy_func3").call { - print_all_trace_info("call") + +probe module("systemtap_test_module2").function("yyy_func2") { + print_all_trace_info("yyy_func2") flag ++ } -probe module("systemtap_test_module2").function("yyy_func4").return { - print_all_trace_info("return") + +probe module("systemtap_test_module2").function("yyy_func3") { + print_all_trace_info("yyy_func3") flag ++ } -probe timer.profile { - if (cpu() == 0 && flag == 2 && probemod() != "systemtap_test_module2") { - print_all_trace_info("profile") - flag ++ - } + +probe module("systemtap_test_module2").function("yyy_func4") { + print_all_trace_info("yyy_func4") + flag ++ } + diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl index f359cd41..6c8aee40 100644 --- a/testsuite/systemtap.context/backtrace.tcl +++ b/testsuite/systemtap.context/backtrace.tcl @@ -5,13 +5,7 @@ set m4 0 set m5 0 set m6 0 -if {[istarget ia64-*-*]} { - set retexp {.*return\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} -} else { - set retexp {.*return\>--\r\n 0x[a-f0-9]+ : kretprobe_trampoline_holder[^\r\n]+\r\n} -} - -spawn stap $srcdir/$subdir/backtrace.stp +spawn stap -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp #exp_internal 1 expect { -timeout 240 @@ -20,69 +14,61 @@ expect { exec echo 0 > /proc/stap_test_cmd exp_continue } - -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} { + + #backtrace from yyy_func2 + -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func2@[^\r\n]+\r\n} { incr m1 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m1 == 1} {incr m1} - exp_continue - } -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m1 == 2} {incr m1} + if {$m1 == 1} {incr m1} exp_continue } -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m1 == 3} {incr m1} + if {$m1 == 2} {incr m1} } } exp_continue } - -re {.*---\r\nthe call stack is 0x[a-f0-9]+ [^\r\n]+\r\n} { + -re {.*--- yyy_func2 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} { incr m2 expect { -timeout 5 - -re {.*call\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m2 == 1} {incr m2} - exp_continue - } -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m2 == 2} {incr m2} + if {$m2 == 1} {incr m2} exp_continue } -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m2 == 3} {incr m2} + if {$m2 == 2} {incr m2} } } exp_continue } - -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} { + + #backtrace from yyy_func3 + -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} { incr m3 expect { -timeout 5 - -re {^Returning from: 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { if {$m3 == 1} {incr m3} exp_continue - } - -re {^Returning to : 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m3 == 2} {incr m3} - exp_continue - } + } -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m3 == 3} {incr m3} + if {$m3 == 2} {incr m3} exp_continue } -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { - if {$m3 == 4} {incr m3} + if {$m3 == 3} {incr m3} } } exp_continue } - -re {.*---\r\nthe return stack is 0x[a-f0-9]+ [^\r\n]+\r\n} { + -re {.*--- yyy_func3 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} { incr m4 expect { -timeout 5 - -re $retexp { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { if {$m4 == 1} {incr m4} exp_continue } @@ -96,58 +82,87 @@ expect { } exp_continue } - -re {.*backtrace from timer.profile:\r\n} { + + #backtrace from yyy_func4 + -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} { incr m5 expect { -timeout 5 - -re {^ 0x[a-f0-9]+[^\r\n]+\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} { if {$m5 == 1} {incr m5} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m5 == 2} {incr m5} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m5 == 3} {incr m5} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m5 == 4} {incr m5} } } exp_continue } - -re {.*---\r\nthe profile stack is 0x[a-f0-9]+[^\r\n]+\r\n} { + -re {.*--- yyy_func4 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} { incr m6 expect { -timeout 5 - -re {.*profile>--\r\n 0x[a-f0-9]+[^\r\n]+\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} { if {$m6 == 1} {incr m6} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m6 == 2} {incr m6} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m6 == 3} {incr m6} + exp_continue + } + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + if {$m6 == 4} {incr m6} } } + exp_continue } - eof {fail "backtrace of yyy_func3, yyy_func4.return and timer.profile. unexpected EOF" } + eof {fail "backtrace of yyy_func[2-4]: unexpected EOF" } } exec kill -INT -[exp_pid] -if {$m1 == 4} { - pass "backtrace of yyy_func3" +if {$m1 == 3} { + pass "backtrace of yyy_func2" } else { - fail "backtrace of yyy_func3 ($m1)" + fail "backtrace of yyy_func2 ($m1)" } -if {$m2 == 4} { - pass "print_stack of yyy_func3" +if {$m2 == 3} { + pass "print_stack of yyy_func2" } else { - fail "print_stack of yyy_func3 ($m2)" + fail "print_stack of yyy_func2 ($m2)" } -if {$m3 == 5} { - pass "backtrace of yyy_func4.return" +if {$m3 == 4} { + pass "backtrace of yyy_func3" } else { - fail "backtrace of yyy_func4.return ($m3)" + fail "backtrace of yyy_func3 ($m3)" } if {$m4 == 4} { - pass "print_stack of yyy_func4.return" + pass "print_stack of yyy_func3" } else { - fail "print_stack of yyy_func4.return ($m4)" + fail "print_stack of yyy_func3 ($m4)" } -if {$m5 == 2} { - pass "backtrace of timer.profile" +if {$m5 == 5} { + pass "backtrace of yyy_func4" } else { - fail "backtrace of timer.profile ($m5)" + fail "backtrace of yyy_func4 ($m5)" } -if {$m6 == 2} { - pass "print_stack of timer.profile" +if {$m6 == 5} { + pass "print_stack of yyy_func4" } else { - fail "print_stack of timer.profile ($m6)" + fail "print_stack of yyy_func4 ($m6)" } + + close wait -- cgit From 580f1a959f79fdd5534a5f2f8daeb415399f38ac Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Fri, 28 Mar 2008 17:01:40 -0400 Subject: dded _stp_read_address() and changed code to use it. --- runtime/ChangeLog | 5 +++++ runtime/copy.c | 32 +++++++++++++++++++++++++------- runtime/stack-i386.c | 4 ++-- runtime/stack-x86_64.c | 2 +- runtime/stack.c | 2 +- runtime/unwind.c | 17 ++++------------- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index e56fa729..d9ea4474 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,8 @@ +2008-03-28 Martin Hunt + + * copy.c (_stp_read_address): New function. Safely read + kernel or userspace. + 2008-03-26 Martin Hunt Fixes to get i386 working. * unwind.c (unwind): Fix types in debug print. diff --git a/runtime/copy.c b/runtime/copy.c index ef3fd223..8891f171 100644 --- a/runtime/copy.c +++ b/runtime/copy.c @@ -9,11 +9,10 @@ * later version. */ -#ifndef _COPY_C_ /* -*- linux-c -*- */ +#ifndef _COPY_C_ /* -*- linux-c -*- */ #define _COPY_C_ #include "string.c" - /** @file copy.c * @brief Functions to copy from user space. */ @@ -26,6 +25,28 @@ * @{ */ +/** Safely read from userspace or kernelspace. + * On success, returns 0. Returns -EFAULT on error. + * + * This uses __get_user() to read from userspace or + * kernelspace. Will not sleep or cause pagefaults when + * called from within a kprobe context. + * + * @param segment . KERNEL_DS for kernel access + * USER_DS for userspace. + */ + +#define _stp_read_address(x, ptr, segment) \ + ({ \ + long ret; \ + mm_segment_t ofs = get_fs(); \ + set_fs(segment); \ + ret = __stp_get_user(x, ptr); \ + set_fs(ofs); \ + ret; \ + }) + + long _stp_strncpy_from_user(char *dst, const char __user *src, long count); //static long __stp_strncpy_from_user(char *dst, const char __user *src, long count); @@ -110,8 +131,7 @@ do { \ * count bytes and returns count. */ -long -_stp_strncpy_from_user(char *dst, const char __user *src, long count) +long _stp_strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, count)) @@ -119,7 +139,6 @@ _stp_strncpy_from_user(char *dst, const char __user *src, long count) return res; } - /** Copy a block of data from user space. * * If some data could not be copied, this function will pad the copied @@ -133,8 +152,7 @@ _stp_strncpy_from_user(char *dst, const char __user *src, long count) * */ -unsigned long -_stp_copy_from_user (char *dst, const char __user *src, unsigned long count) +unsigned long _stp_copy_from_user(char *dst, const char __user *src, unsigned long count) { if (count) { if (access_ok(VERIFY_READ, src, count)) diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index d7c2c201..c99b4a8c 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -18,7 +18,7 @@ static void _stp_stack_print_fallback(unsigned long context, unsigned long stack { unsigned long addr; while (_stp_valid_stack_ptr(context, stack)) { - if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) { + if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) { /* cannot access stack. give up. */ return; } @@ -43,7 +43,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) #endif /* STAPCONF_X86_UNIREGS */ while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { - if (unlikely(__stp_get_user(addr, (unsigned long *)(ebp + 4)))) { + if (unlikely(_stp_read_address(addr, (unsigned long *)(ebp + 4), KERNEL_DS))) { /* cannot access stack. give up. */ return; } diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 846653be..96f82004 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -15,7 +15,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose) { unsigned long addr; while (stack & (THREAD_SIZE - 1)) { - if (unlikely(__stp_get_user(addr, (unsigned long *)stack))) { + if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) { /* cannot access stack. give up. */ return; } diff --git a/runtime/stack.c b/runtime/stack.c index eefdf715..772c5baf 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -62,7 +62,7 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan } _stp_print_char('\n'); } else if (pi) - _stp_printf("%p %p ", (int64_t) _stp_ret_addr_r(pi), (int64_t) REG_IP(regs)); + _stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs)); else _stp_printf("%p ", (int64_t) REG_IP(regs)); diff --git a/runtime/unwind.c b/runtime/unwind.c index e8cba72e..f0010372 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -321,7 +321,7 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy return 0; } if ((ptrType & DW_EH_PE_indirect) - && __stp_get_user(value, (unsigned long *)value)) + && _stp_read_address(value, (unsigned long *)value, KERNEL_DS)) return 0; *pLoc = ptr.p8; @@ -676,7 +676,7 @@ int unwind(struct unwind_frame_info *frame) #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) const u32 *fde, *cie = NULL; const u8 *ptr = NULL, *end = NULL; - unsigned long pc = UNW_PC(frame); + unsigned long pc = UNW_PC(frame) - frame->call_frame; unsigned long tableSize, startLoc = 0, endLoc = 0, cfa; unsigned i; signed ptrType = -1; @@ -684,15 +684,6 @@ int unwind(struct unwind_frame_info *frame) struct _stp_module *m; struct unwind_state state; - if (pc != _stp_kretprobe_trampoline) - pc -= frame->call_frame; - else { - unsigned long a1, a2, *addr = (unsigned long *)UNW_SP(frame); - __stp_get_user(a1, addr); - __stp_get_user(a2, addr+1); - dbug_unwind(1, "TRAMPOLINE: SP=%lx *SP=%lx *(SP+1)=%lx\n", UNW_SP(frame), a1, a2); - return -EINVAL; - } dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame)); if (UNW_PC(frame) == 0) @@ -933,7 +924,7 @@ int unwind(struct unwind_frame_info *frame) dbug_unwind(2, "addr=%lx width=%d\n", addr, reg_info[i].width); switch (reg_info[i].width) { #define CASE(n) case sizeof(u##n): \ - if (unlikely(__stp_get_user(FRAME_REG(i, u##n), (u##n *)addr))) \ + if (unlikely(_stp_read_address(FRAME_REG(i, u##n), (u##n *)addr, KERNEL_DS))) \ goto copy_failed;\ dbug_unwind(1, "set register %d to %lx\n", i, (long)FRAME_REG(i,u##n));\ break @@ -952,7 +943,7 @@ int unwind(struct unwind_frame_info *frame) return 0; copy_failed: - dbug_unwind(1, "_stp_get_user failed to access memory\n"); + dbug_unwind(1, "_stp_read_address failed to access memory\n"); err: read_unlock(&m->lock); return -EIO; -- cgit From 6567250495117bfa4eb8b58c805897133c0d3ff2 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Fri, 28 Mar 2008 17:04:22 -0400 Subject: Fix regression. --- runtime/stack-i386.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index c99b4a8c..11919b29 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -69,7 +69,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */ /* FIXME: is there a way to unwind across kretprobe trampolines? */ if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline)) - _stp_stack_print_fallback(UNW_SP(&info), verbose); + _stp_stack_print_fallback(context, UNW_SP(&info), verbose); break; } #endif /* CONFIG_FRAME_POINTER */ -- cgit From 20d2c2c26b42b27a4881a46364a33330b2a6ea31 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Sun, 30 Mar 2008 19:47:51 -0400 Subject: Support for kernels built with CONFIG_FRAME_POINTER --- runtime/ChangeLog | 9 +++++++++ runtime/copy.c | 2 +- runtime/runtime.h | 7 +++++++ runtime/stack-arm.c | 4 ++-- runtime/stack-i386.c | 4 ++-- runtime/transport/ChangeLog | 5 +++++ runtime/transport/symbols.c | 5 ++++- runtime/transport/transport.c | 2 +- runtime/unwind/i386.h | 2 +- runtime/unwind/x86_64.h | 5 ++++- 10 files changed, 36 insertions(+), 9 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index d9ea4474..7c6dbbea 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,12 @@ +2008-03-30 Martin Hunt + + * runtime.h (STP_USE_FRAME_POINTER): Define when frame pointers + are available in the kernel and can be used. + * stack-arm.c: Use STP_USE_FRAME_POINTER. + * stack-i386.c: Ditto. + * unwind/i386.h: Ditto. + * unwind/x86_64.h: Ditto. + 2008-03-28 Martin Hunt * copy.c (_stp_read_address): New function. Safely read diff --git a/runtime/copy.c b/runtime/copy.c index 8891f171..6bb22762 100644 --- a/runtime/copy.c +++ b/runtime/copy.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Copy from user space functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * Copyright (C) 2005 Intel Corporation. * * This file is part of systemtap, and is free software. You can diff --git a/runtime/runtime.h b/runtime/runtime.h index b9a9c778..6d8d9dc9 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -70,6 +70,13 @@ static struct #define MAXSTRINGLEN 128 #endif +#ifdef CONFIG_FRAME_POINTER +/* Just because frame pointers are available does not mean we can trust them. */ +#if defined (__i386__) || defined (__arm__) +#define STP_USE_FRAME_POINTER +#endif +#endif + #include "alloc.c" #include "print.c" #include "string.c" diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c index 0c8ce450..9b0b772d 100644 --- a/runtime/stack-arm.c +++ b/runtime/stack-arm.c @@ -33,7 +33,7 @@ static int __init find_str_pc_offset(void) static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) { -#if defined(CONFIG_FRAME_POINTER) +#ifdef STP_USE_FRAME_POINTER int pc_offset = find_str_pc_offset(); unsigned long *fp = (unsigned long *)regs->ARM_fp; unsigned long *next_fp, *pc; @@ -68,5 +68,5 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) fp = next_fp; } -#endif +#endif /* STP_USE_FRAME_POINTER */ } diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index 11919b29..20c8eda5 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -32,7 +32,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) unsigned long *stack = (unsigned long *)®_SP(regs); unsigned long context = (unsigned long)stack & ~(THREAD_SIZE - 1); -#ifdef CONFIG_FRAME_POINTER +#ifdef STP_USE_FRAME_POINTER /* FIXME: need to use _stp_func_print() and safe copy */ unsigned long addr; @@ -72,5 +72,5 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) _stp_stack_print_fallback(context, UNW_SP(&info), verbose); break; } -#endif /* CONFIG_FRAME_POINTER */ +#endif /* STP_USE_FRAME_POINTER */ } diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 2db40a12..b55657e9 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,8 @@ +2008-03-30 Martin Hunt + + * symbols.c (_stp_init_modules): If using frames, don't + request unwind info. + 2008-03-25 Martin Hunt * control.c (_stp_ctl_write_dbug): Insert missing break. diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 83a3a635..118d5693 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -581,7 +581,10 @@ static int _stp_init_modules(void) /* unlocks the list */ modules_op->stop(NULL, NULL); -#ifndef CONFIG_FRAME_POINTER +#ifdef STP_USE_FRAME_POINTER + /* done with modules, now go */ + _stp_ctl_send(STP_TRANSPORT, NULL, 0); +#else /* now that we have all the modules, ask for their unwind info */ { unsigned long flags; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index aa96a50e..8f59584d 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -259,7 +259,7 @@ int _stp_transport_init(void) goto err3; _stp_transport_state = 1; - + dbug_trans(1, "calling init_kernel_symbols\n"); if (_stp_init_kernel_symbols() < 0) goto err4; diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index cb2efab7..354807a0 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -30,7 +30,7 @@ struct unwind_frame_info #define UNW_PC(frame) (frame)->regs.eip #define UNW_SP(frame) (frame)->regs.esp -#ifdef CONFIG_FRAME_POINTER +#ifdef STP_USE_FRAME_POINTER #define UNW_FP(frame) (frame)->regs.ebp #define FRAME_RETADDR_OFFSET 4 #define FRAME_LINK_OFFSET 0 diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index 6e6e521f..48838490 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -35,13 +35,16 @@ struct unwind_frame_info #define UNW_PC(frame) (frame)->regs.rip #define UNW_SP(frame) (frame)->regs.rsp -#ifdef CONFIG_FRAME_POINTER + +#if 0 /* STP_USE_FRAME_POINTER */ +/* Frame pointers not implemented in x86_64 currently */ #define UNW_FP(frame) (frame)->regs.rbp #define FRAME_RETADDR_OFFSET 8 #define FRAME_LINK_OFFSET 0 #define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1)) #define STACK_TOP(tsk) ((tsk)->thread.rsp0) #endif + /* Might need to account for the special exception and interrupt handling stacks here, since normally EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER, -- cgit From a18db0a7895c33bb5246a15f715b30fbd006bd9b Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Mon, 31 Mar 2008 10:05:38 -0400 Subject: Remove misleading error message. --- runtime/transport/ChangeLog | 4 ++++ runtime/transport/transport.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index b55657e9..56f4477b 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,7 @@ +2008-03-31 Martin Hunt + + * transport.c (_stp_get_root_dir): Remove misleading error message. + 2008-03-30 Martin Hunt * symbols.c (_stp_init_modules): If using frames, don't diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 8f59584d..7ff9c8c0 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -369,7 +369,6 @@ static struct dentry *_stp_get_root_dir(const char *name) _stp_lock_inode(sb->s_root->d_inode); root = lookup_one_len(name, sb->s_root, strlen(name)); _stp_unlock_inode(sb->s_root->d_inode); - errk("ERROR: root=%p\n", root); if (!IS_ERR(root)) dput(root); else { -- cgit From b45613ad2a9740217ad3050adc6fcd038286ce88 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Mon, 31 Mar 2008 11:05:13 -0400 Subject: Add new define STP_USE_DWARF_UNWINDER which is set based on which archs work with the unwinder. --- runtime/ChangeLog | 4 ++++ runtime/runtime.h | 5 +++++ runtime/transport/ChangeLog | 2 ++ runtime/transport/symbols.c | 11 ++++++----- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 7c6dbbea..e6d8ed72 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,7 @@ +2008-03-31 Martin Hunt + + * runtime.h (STP_USE_DWARF_UNWINDER): Define. + 2008-03-30 Martin Hunt * runtime.h (STP_USE_FRAME_POINTER): Define when frame pointers diff --git a/runtime/runtime.h b/runtime/runtime.h index 6d8d9dc9..8d267173 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -77,6 +77,11 @@ static struct #endif #endif +/* dwarf unwinder only tested so far on i386 and x86_64 */ +#if !defined(STP_USE_FRAME_BUFFER) && (defined(__i386__) || defined(__x86_64__)) +#define STP_USE_DWARF_UNWINDER +#endif + #include "alloc.c" #include "print.c" #include "string.c" diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 56f4477b..0bb62497 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,5 +1,7 @@ 2008-03-31 Martin Hunt + * symbols.c (_stp_init_modules): Use STP_USE_DWARF_UNWINDER. + * transport.c (_stp_get_root_dir): Remove misleading error message. 2008-03-30 Martin Hunt diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 118d5693..8bab1e70 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -581,10 +581,7 @@ static int _stp_init_modules(void) /* unlocks the list */ modules_op->stop(NULL, NULL); -#ifdef STP_USE_FRAME_POINTER - /* done with modules, now go */ - _stp_ctl_send(STP_TRANSPORT, NULL, 0); -#else +#ifdef STP_USE_DWARF_UNWINDER /* now that we have all the modules, ask for their unwind info */ { unsigned long flags; @@ -616,7 +613,11 @@ static int _stp_init_modules(void) left -= 2; _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left); } -#endif +#else + /* done with modules, now go */ + _stp_ctl_send(STP_TRANSPORT, NULL, 0); +#endif /* STP_USE_DWARF_UNWINDER */ + return 0; } -- cgit From 073b6ba57a498c3c97426f6f6d0666f1f5eb30d4 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 1 Apr 2008 22:37:12 -0400 Subject: reincarnate vim/ directory in this branch to match master --- vim/filetype.vim | 10 ++++++ vim/ftplugin/stap.vim | 25 +++++++++++++ vim/indent/stap.vim | 35 +++++++++++++++++++ vim/syntax/stap.vim | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 vim/filetype.vim create mode 100644 vim/ftplugin/stap.vim create mode 100644 vim/indent/stap.vim create mode 100644 vim/syntax/stap.vim diff --git a/vim/filetype.vim b/vim/filetype.vim new file mode 100644 index 00000000..8c1fdfbd --- /dev/null +++ b/vim/filetype.vim @@ -0,0 +1,10 @@ +" Vim support file to detect file types +" Language: SystemTap +" Maintainer: Josh Stone +" Last Change: 2005 Dec 16 +" Note: this overrides the default *.stp mapping to "Stored Procedures" +" It would be nice to find a way to intelligently detect this. + +" SystemTap scripts +au BufNewFile,BufRead *.stp setf stap + diff --git a/vim/ftplugin/stap.vim b/vim/ftplugin/stap.vim new file mode 100644 index 00000000..de49a4f1 --- /dev/null +++ b/vim/ftplugin/stap.vim @@ -0,0 +1,25 @@ +" Vim filetype plugin file +" Language: SystemTap +" Maintainer: Josh Stone +" Last Change: 2005 Dec 15 + +" Only do this when not done yet for this buffer +if exists("b:did_ftplugin") + finish +endif + +" Don't load another plugin for this buffer +let b:did_ftplugin = 1 + +set cpo-=C + +let b:undo_ftplugin = "setl cin< fo< com<" + +setlocal cindent + +" Set 'formatoptions' to break comment lines but not other lines, +" and insert the comment leader when hitting or using "o". +setlocal fo-=t fo+=croql + +" Set 'comments' to format dashed lists in comments. +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://,:# diff --git a/vim/indent/stap.vim b/vim/indent/stap.vim new file mode 100644 index 00000000..16658d6c --- /dev/null +++ b/vim/indent/stap.vim @@ -0,0 +1,35 @@ +" Vim indent file +" Language: SystemTap +" Maintainer: Josh Stone +" Last Change: 2005 Dec 15 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" SystemTap indenting works *mostly* the same as C, so this gets things pretty +" close. For 'real' SystemTap indenting, we would have to write a custom +" indentexpr function. + +" indenting is similar to C, so start there... +setlocal cindent + +" Statements don't require a ';', so don't indent following lines +setlocal cino=+0 + +" Known issues: +" - need to detect when following lines are a continuation of the previous +" statement, and indent appropriately. +" - one-liners with control flow try to indent the next line if there's no +" ';'. For example: +" if (my_condition) break +" do_work() +" The second line should not be indented. +" - The embedded-C braces do not line up correctly +" - Preprocessor braces don't line up correctly, and internals of the +" preprocessor aren't getting any special handling. +" - Embedded-C statements across multiple lines don't indent +" - '#' comments don't maintain indenting (they get treated like C +" preprocessor statements) diff --git a/vim/syntax/stap.vim b/vim/syntax/stap.vim new file mode 100644 index 00000000..86c7d260 --- /dev/null +++ b/vim/syntax/stap.vim @@ -0,0 +1,97 @@ +" Vim syntax file +" Language: SystemTap +" Maintainer: Josh Stone +" Last Change: 2005 Dec 20 + +" For version 5.x: Clear all syntax items +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syn clear +elseif exists("b:current_syntax") + finish +endif + +syn keyword stapStatement contained break continue return next delete containedin=stapBlock +syn keyword stapRepeat contained while for foreach in containedin=stapBlock +syn keyword stapConditional contained if else containedin=stapBlock +syn keyword stapDeclaration global probe function +syn keyword stapType string long + +syn region stapProbeDec start="\"lc=5 end="{"me=s-1 contains=stapString,stapNumber +syn match stapProbe contained "\<\w\+\>" containedin=stapProbeDec + +syn region stapFuncDec start="\"lc=8 end=":\|("me=s-1 contains=stapString,stapNumber +syn match stapFuncCall contained "\<\w\+\ze\(\s\|\n\)*(" containedin=stapBlock +syn match stapFunc contained "\<\w\+\>" containedin=stapFuncDec,stapFuncCall + +syn match stapStat contained "@\<\w\+\ze\(\s\|\n\)*(" containedin=stapBlock + +" decimal number +syn match stapNumber "\<\d\+\>" containedin=stapBlock +" octal number +syn match stapNumber "\<0\o\+\>" contains=stapOctalZero containedin=stapBlock +" Flag the first zero of an octal number as something special +syn match stapOctalZero contained "\<0" +" flag an octal number with wrong digits +syn match stapOctalError "\<0\o*[89]\d*" containedin=stapBlock +" hex number +syn match stapNumber "0x\x\+\>" containedin=stapBlock + +syn region stapString oneline start=+"+ skip=+\\"+ end=+"+ containedin=stapBlock + +syn region stapPreProc fold start="%(" end="%)" contains=stapNumber,stapString containedin=ALL +syn keyword stapPreProcCond contained kernel_v kernel_vr arch containedin=stapPreProc + +syn include @C syntax/c.vim +syn keyword stapCMacro contained THIS CONTEXT containedin=@C,stapCBlock +syn region stapCBlock fold matchgroup=stapCBlockDelims start="%{"rs=e end="%}"re=s contains=@C + +syn region stapBlock fold matchgroup=stapBlockEnds start="{"rs=e end="}"re=s containedin=stapBlock + +syn keyword stapTodo contained TODO FIXME XXX + +syn match stapComment "#.*" contains=stapTodo containedin=stapBlock +syn match stapComment "//.*" contains=stapTodo containedin=stapBlock +syn region stapComment matchgroup=stapComment start="/\*" end="\*/" contains=stapTodo,stapCommentBad containedin=stapBlock +syn match stapCommentBad contained "/\*" + +" treat ^#! as special +syn match stapSharpBang "^#!.*" + + +" define the default highlighting +" For version 5.7 and earlier: only when not done already +" For version 5.8 and later: only when an item doesn't have highlightling yet +if version >= 508 || !exists("did_stap_syn_inits") + if version < 508 + let did_stap_syn_inits = 1 + command -nargs=+ HiLink hi link + else + command -nargs=+ HiLink hi def link + endif + + HiLink stapNumber Number + HiLink stapOctalZero PreProc " c.vim does it this way... + HiLink stapOctalError Error + HiLink stapString String + HiLink stapTodo Todo + HiLink stapComment Comment + HiLink stapCommentBad Error + HiLink stapSharpBang PreProc + HiLink stapCBlockDelims Special + HiLink stapCMacro Macro + HiLink stapStatement Statement + HiLink stapConditional Conditional + HiLink stapRepeat Repeat + HiLink stapType Type + HiLink stapProbe Function + HiLink stapFunc Function + HiLink stapStat Function + HiLink stapPreProc PreProc + HiLink stapPreProcCond Special + HiLink stapDeclaration Typedef + + delcommand HiLink +endif + +let b:current_syntax = "stap" -- cgit From fa670082537aea7f090bc8dcfab69ac5f62546bc Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Wed, 9 Apr 2008 11:32:50 -0400 Subject: Change stap to get kernel symbols from debuginfo and compile them into the module. --- ChangeLog | 5 ++ runtime/transport/ChangeLog | 6 ++ runtime/transport/symbols.c | 23 ++++++-- translate.cxx | 137 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 138 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8eb41250..d193233b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-04-09 Martin Hunt + + * translate.cxx (emit_symbol_data): When available, + grab symbols from debuginfo instead of /proc/kallsyms. + 2008-03-31 Frank Ch. Eigler * configure.ac: Bump version to 0.7. diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 0bb62497..b3a159e3 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,9 @@ +2008-04-09 Martin Hunt + + * symbols.c (_stp_init_kernel_symbols): Print error + messages and exit if symbol lookups fail. + (_stp_init_modules): Lookup modules_op. + 2008-03-31 Martin Hunt * symbols.c (_stp_init_modules): Use STP_USE_DWARF_UNWINDER. diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 8bab1e70..b0e7c319 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -187,8 +187,8 @@ static int _stp_init_kernel_symbols(void) { _stp_modules[0] = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); if (_stp_modules[0] == NULL) { - errk("cannot allocate memory\n"); - return -EFAULT; + _dbug("cannot allocate memory\n"); + return -1; } _stp_modules[0]->symbols = _stp_kernel_symbols; _stp_modules[0]->num_symbols = _stp_num_kernel_symbols; @@ -197,11 +197,21 @@ static int _stp_init_kernel_symbols(void) /* Note: this mapping is used by kernel/_stext pseudo-relocations. */ _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); + if (_stp_modules[0]->text == 0) { + _dbug("Lookup of _stext failed. Exiting.\n"); + return -1; + } _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); + if (_stp_modules[0]->data == 0) { + _dbug("Lookup of _etext failed. Exiting.\n"); + return -1; + } _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text; _stp_modules_by_addr[0] = _stp_modules[0]; _stp_kretprobe_trampoline = _stp_kallsyms_lookup_name("kretprobe_trampoline"); + /* Lookup failure is not fatal */ + return 0; } @@ -559,14 +569,19 @@ static struct notifier_block _stp_module_load_nb = { }; #include -extern unsigned long _stp_modules_op; /* from stap */ + static int _stp_init_modules(void) { loff_t pos = 0; void *res; struct module *mod; + const struct seq_operations *modules_op = (const struct seq_operations *)_stp_kallsyms_lookup_name("modules_op"); + + if (modules_op == NULL) { + _dbug("Lookup of modules_op failed.\n"); + return -1; + } - const struct seq_operations *modules_op = (const struct seq_operations *)_stp_modules_op; /* Use the seq_file interface to safely get a list of installed modules */ res = modules_op->start(NULL, &pos); while (res) { diff --git a/translate.cxx b/translate.cxx index baa64741..dc6dd9f8 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4356,45 +4356,124 @@ c_unparser::visit_hist_op (hist_op*) assert(false); } + +static map< Dwarf_Addr, string> addrmap; + +static int +kernel_filter (const char *module, const char *file __attribute__((unused))) +{ + return !strcmp(module,"kernel"); +} + +static int +get_symbols (Dwfl_Module *m, + void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ + int syments = dwfl_module_getsymtab(m); + assert(syments); + for (int i = 1; i < syments; ++i) + { + GElf_Sym sym; + const char *name = dwfl_module_getsym(m, i, &sym, NULL); + if (name) { + if (GELF_ST_TYPE (sym.st_info) == STT_FUNC || + strcmp(name, "_etext") == 0 || + strcmp(name, "_stext") == 0 || + strcmp(name, "modules_op") == 0) + addrmap[sym.st_value] = name; + } + } + return DWARF_CB_OK; +} + +int +emit_symbol_data_from_debuginfo(systemtap_session& s, ofstream& kallsyms_out) +{ + static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug"; + static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); + + static char *debuginfo_path = (debuginfo_env_arr ? + debuginfo_env_arr : debuginfo_path_arr); + + static const Dwfl_Callbacks kernel_callbacks = + { + dwfl_linux_kernel_find_elf, + dwfl_standard_find_debuginfo, + dwfl_offline_section_address, + & debuginfo_path + }; + + Dwfl *dwfl = dwfl_begin (&kernel_callbacks); + if (!dwfl) + throw semantic_error ("cannot open dwfl"); + dwfl_report_begin (dwfl); + + int rc = dwfl_linux_kernel_report_offline (dwfl, + s.kernel_release.c_str(), + kernel_filter); + dwfl_report_end (dwfl, NULL, NULL); + if (rc < 0) + return rc; + + dwfl_getmodules (dwfl, &get_symbols, NULL, 0); + dwfl_end(dwfl); + + int i = 0; + map< Dwarf_Addr, string>::iterator pos; + kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {"; + for (pos = addrmap.begin(); pos != addrmap.end(); pos++) { + kallsyms_out << " { 0x" << hex << pos->first << ", " << "\"" << pos->second << "\" },\n"; + i++; + } + + kallsyms_out << "};\n"; + kallsyms_out << "unsigned _stp_num_kernel_symbols = " << dec << i << ";\n"; + return i == 0; +} + int emit_symbol_data (systemtap_session& s) { - // Instead of processing elf symbol tables, for now we just snatch - // /proc/kallsyms and convert it to our use. - unsigned i=0; - ifstream kallsyms("/proc/kallsyms"); char kallsyms_outbuf [4096]; ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str()); kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf, - sizeof(kallsyms_outbuf)); - + sizeof(kallsyms_outbuf)); s.op->newline() << "\n\n#include \"stap-symbols.h\""; - kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {"; - string lastaddr, modules_op_addr; - - while (! kallsyms.eof()) - { - string addr, type, sym; - kallsyms >> addr >> type >> sym >> ws; - if (kallsyms.peek() == '[') - break; - - // NB: kallsyms includes some duplicate addresses - if ((type == "t" || type == "T" || type == "A") && lastaddr != addr) - { - kallsyms_out << " { 0x" << addr << ", " << "\"" << sym << "\" },\n"; - lastaddr = addr; - i ++; - } - else if (sym == "modules_op") - modules_op_addr = addr; - } - kallsyms_out << "};\n"; - kallsyms_out << "unsigned _stp_num_kernel_symbols = " << i << ";\n"; - kallsyms_out << "unsigned long _stp_modules_op = 0x" << modules_op_addr << ";\n"; + // FIXME for non-debuginfo use. + if (true) { + return emit_symbol_data_from_debuginfo(s, kallsyms_out); + } else { + // For symbol-table only operation, we don't have debuginfo, + // so parse /proc/kallsyms. + ifstream kallsyms("/proc/kallsyms"); + string lastaddr, modules_op_addr; + + kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {"; + while (! kallsyms.eof()) + { + string addr, type, sym; + kallsyms >> addr >> type >> sym >> ws; + + if (kallsyms.peek() == '[') + break; + + // NB: kallsyms includes some duplicate addresses + if ((type == "t" || type == "T" || type == "A" || sym == "modules_op") && lastaddr != addr) + { + kallsyms_out << " { 0x" << addr << ", " << "\"" << sym << "\" },\n"; + lastaddr = addr; + i ++; + } + } + kallsyms_out << "};\n"; + kallsyms_out << "unsigned _stp_num_kernel_symbols = " << i << ";\n"; + } return (i == 0); } -- cgit From 404bf86f4c825eafe4ad9f34f676c0e37464cfe7 Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Wed, 9 Apr 2008 15:24:14 -0400 Subject: Include string.h --- translate.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/translate.cxx b/translate.cxx index dc6dd9f8..a72cb1d8 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4359,6 +4359,8 @@ c_unparser::visit_hist_op (hist_op*) static map< Dwarf_Addr, string> addrmap; +#include + static int kernel_filter (const char *module, const char *file __attribute__((unused))) { -- cgit From b53c1feef55dc74501a90257e4beff6c1a9cf03b Mon Sep 17 00:00:00 2001 From: Martin Hunt Date: Wed, 9 Apr 2008 17:02:40 -0400 Subject: Fixes for 2.6.25 pt_regs changes. --- ChangeLog | 3 +++ buildrun.cxx | 2 -- runtime/stack-x86_64.c | 3 +-- runtime/unwind/i386.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- runtime/unwind/x86_64.h | 43 +++++++++++++++++++++++++++++++++-- 5 files changed, 102 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index d193233b..f2959b3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2008-04-09 Martin Hunt + * buildrun.cxx (run_pass): Remove unused "-d" option + passed to staprun. + * translate.cxx (emit_symbol_data): When available, grab symbols from debuginfo instead of /proc/kallsyms. diff --git a/buildrun.cxx b/buildrun.cxx index f3e72272..a186326f 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -254,8 +254,6 @@ run_pass (systemtap_session& s) + (s.verbose>2 ? "-v " : "") + (s.output_file.empty() ? "" : "-o " + s.output_file + " "); - staprun_cmd += "-d " + stringify(getpid()) + " "; - if (s.cmd != "") staprun_cmd += "-c " + cmdstr_quoted(s.cmd) + " "; diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 96f82004..ae8e446d 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -8,8 +8,6 @@ * later version. */ -// todo: don't use unwinder for kernel if CONFIG_FRAME - /* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ static void _stp_stack_print_fallback(unsigned long stack, int verbose) { @@ -26,6 +24,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose) static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels) { + // FIXME: large stack allocation struct unwind_frame_info info; arch_unw_init_frame_info(&info, regs); diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index 354807a0..1f69b4a9 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -28,6 +28,35 @@ struct unwind_frame_info unsigned call_frame:1; }; +#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) + +#ifdef STAPCONF_X86_UNIREGS + +#define UNW_PC(frame) (frame)->regs.ip +#define UNW_SP(frame) (frame)->regs.sp +#ifdef STP_USE_FRAME_POINTER +#define UNW_FP(frame) (frame)->regs.bp +#define FRAME_RETADDR_OFFSET 4 +#define FRAME_LINK_OFFSET 0 +#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.sp0) +#define STACK_TOP(tsk) ((tsk)->thread.sp0) +#else +#define UNW_FP(frame) ((void)(frame), 0) +#endif + +#define UNW_REGISTER_INFO \ + PTREGS_INFO(ax), \ + PTREGS_INFO(cx), \ + PTREGS_INFO(dx), \ + PTREGS_INFO(bx), \ + PTREGS_INFO(sp), \ + PTREGS_INFO(bp), \ + PTREGS_INFO(si), \ + PTREGS_INFO(di), \ + PTREGS_INFO(ip) + +#else /* !STAPCONF_X86_UNIREGS */ + #define UNW_PC(frame) (frame)->regs.eip #define UNW_SP(frame) (frame)->regs.esp #ifdef STP_USE_FRAME_POINTER @@ -39,7 +68,6 @@ struct unwind_frame_info #else #define UNW_FP(frame) ((void)(frame), 0) #endif -#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) #define UNW_REGISTER_INFO \ PTREGS_INFO(eax), \ @@ -52,6 +80,8 @@ struct unwind_frame_info PTREGS_INFO(edi), \ PTREGS_INFO(eip) +#endif /* STAPCONF_X86_UNIREGS */ + #define UNW_DEFAULT_RA(raItem, dataAlign) \ ((raItem).where == Memory && \ !((raItem).value * (dataAlign) + 4)) @@ -62,9 +92,16 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, if (user_mode_vm(regs)) info->regs = *regs; else { +#ifdef STAPCONF_X86_UNIREGS + memcpy(&info->regs, regs, offsetof(struct pt_regs, sp)); + info->regs.sp = (unsigned long)®s->sp; + info->regs.ss = __KERNEL_DS; +#else memcpy(&info->regs, regs, offsetof(struct pt_regs, esp)); info->regs.esp = (unsigned long)®s->esp; - info->regs.xss = __KERNEL_DS; + info->regs.xss = __KERNEL_DS; +#endif + } info->call_frame = 1; } @@ -72,6 +109,15 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, static inline void arch_unw_init_blocked(struct unwind_frame_info *info) { memset(&info->regs, 0, sizeof(info->regs)); +#ifdef STAPCONF_X86_UNIREGS + info->regs.ip = info->task->thread.ip; + info->regs.cs = __KERNEL_CS; + __get_user(info->regs.bp, (long *)info->task->thread.sp); + info->regs.sp = info->task->thread.sp; + info->regs.ss = __KERNEL_DS; + info->regs.ds = __USER_DS; + info->regs.es = __USER_DS; +#else info->regs.eip = info->task->thread.eip; info->regs.xcs = __KERNEL_CS; __get_user(info->regs.ebp, (long *)info->task->thread.esp); @@ -79,6 +125,8 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) info->regs.xss = __KERNEL_DS; info->regs.xds = __USER_DS; info->regs.xes = __USER_DS; +#endif + } @@ -87,11 +135,18 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info) #if 0 /* This can only work when selector register and EFLAGS saves/restores are properly annotated (and tracked in UNW_REGISTER_INFO). */ return user_mode_vm(&info->regs); +#else +#ifdef STAPCONF_X86_UNIREGS + return info->regs.ip < PAGE_OFFSET + || (info->regs.ip >= __fix_to_virt(FIX_VDSO) + && info->regs.ip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE) + || info->regs.sp < PAGE_OFFSET; #else return info->regs.eip < PAGE_OFFSET || (info->regs.eip >= __fix_to_virt(FIX_VDSO) && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE) || info->regs.esp < PAGE_OFFSET; +#endif #endif } diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index 48838490..5eb3a58f 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -33,8 +33,13 @@ struct unwind_frame_info unsigned call_frame:1; }; +#ifdef STAPCONF_X86_UNIREGS +#define UNW_PC(frame) (frame)->regs.ip +#define UNW_SP(frame) (frame)->regs.sp +#else #define UNW_PC(frame) (frame)->regs.rip #define UNW_SP(frame) (frame)->regs.rsp +#endif /* STAPCONF_X86_UNIREGS */ #if 0 /* STP_USE_FRAME_POINTER */ /* Frame pointers not implemented in x86_64 currently */ @@ -54,6 +59,26 @@ struct unwind_frame_info not desirable. */ #define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) +#ifdef STAPCONF_X86_UNIREGS +#define UNW_REGISTER_INFO \ + PTREGS_INFO(ax), \ + PTREGS_INFO(dx), \ + PTREGS_INFO(cx), \ + PTREGS_INFO(bx), \ + PTREGS_INFO(si), \ + PTREGS_INFO(di), \ + PTREGS_INFO(bp), \ + PTREGS_INFO(sp), \ + PTREGS_INFO(r8), \ + PTREGS_INFO(r9), \ + PTREGS_INFO(r10), \ + PTREGS_INFO(r11), \ + PTREGS_INFO(r12), \ + PTREGS_INFO(r13), \ + PTREGS_INFO(r14), \ + PTREGS_INFO(r15), \ + PTREGS_INFO(ip) +#else #define UNW_REGISTER_INFO \ PTREGS_INFO(rax), \ PTREGS_INFO(rdx), \ @@ -72,6 +97,7 @@ struct unwind_frame_info PTREGS_INFO(r14), \ PTREGS_INFO(r15), \ PTREGS_INFO(rip) +#endif /* STAPCONF_X86_UNIREGS */ #define UNW_DEFAULT_RA(raItem, dataAlign) \ ((raItem).where == Memory && \ @@ -89,11 +115,18 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) extern const char thread_return[]; memset(&info->regs, 0, sizeof(info->regs)); - info->regs.rip = (unsigned long)thread_return; info->regs.cs = __KERNEL_CS; + info->regs.ss = __KERNEL_DS; + +#ifdef STAPCONF_X86_UNIREGS + info->regs.ip = (unsigned long)thread_return; + __get_user(info->regs.bp, (unsigned long *)info->task->thread.sp); + info->regs.sp = info->task->thread.sp; +#else + info->regs.rip = (unsigned long)thread_return; __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp); info->regs.rsp = info->task->thread.rsp; - info->regs.ss = __KERNEL_DS; +#endif } static inline int arch_unw_user_mode(const struct unwind_frame_info *info) @@ -101,11 +134,17 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info) #if 0 /* This can only work when selector register saves/restores are properly annotated (and tracked in UNW_REGISTER_INFO). */ return user_mode(&info->regs); +#else +#ifdef STAPCONF_X86_UNIREGS + return (long)info->regs.ip >= 0 + || (info->regs.ip >= VSYSCALL_START && info->regs.ip < VSYSCALL_END) + || (long)info->regs.sp >= 0; #else return (long)info->regs.rip >= 0 || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END) || (long)info->regs.rsp >= 0; #endif +#endif } #endif /* _STP_X86_64_UNWIND_H */ -- cgit From 0f3f43c992867e6b1a963872b83ea1dcbf7ddd96 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 11 Apr 2008 09:52:25 -0500 Subject: 2008-04-11 David Smith * .gitignore: Added git_version.h. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4984fad5..3f042854 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ stapio stap_merge SNAPSHOT *.o +git_version.h -- cgit From 342d3f9693ea4eead68ba8ff841132a7adc7776b Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 11 Apr 2008 09:52:55 -0500 Subject: 2008-04-11 David Smith * elaborate.h (struct derived_probe_group): Added emit_module_header virtual function. * translate.cxx (c_unparser::emit_common_header): Calls each probe group's emit_module_header function. (translate_pass): Moved inclusion of linux/marker.h to mark_derived_probe_group::emit_module_header(). * tapsets.cxx (struct be_derived_probe_group): Added empty emit_module_header function. (struct timer_derived_probe_group): Ditto. (struct profile_derived_probe_group): Ditto. (struct procfs_derived_probe_group): Ditto. (struct hrtimer_derived_probe_group): Ditto. (struct perfmon_derived_probe_group): Ditto. (dwarf_derived_probe_group::emit_module_header): Moved kprobes kernel check from emit_module_decls() to here. (uprobe_derived_probe_group::emit_module_header): Moved uprobe kernel check from emit_module_decls() to here. (uprobe_derived_probe_group::emit_module_decls): Moved uprobe kernel check to emit_module_header(). (mark_derived_probe_group::emit_module_header): Moved marker kernel check from emit_module_decls and translate_pass() to here. (uprobe_derived_probe_group::emit_module_decls): Moved marker kernel check to emit_module_header(). --- ChangeLog | 26 ++++++++++++++++++++++++++ elaborate.h | 6 ++++++ tapsets.cxx | 53 +++++++++++++++++++++++++++++++++++++++++++---------- translate.cxx | 9 +++++---- 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 65660ac0..cbf6e83e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2008-04-11 David Smith + + * elaborate.h (struct derived_probe_group): Added + emit_module_header virtual function. + * translate.cxx (c_unparser::emit_common_header): Calls each probe + group's emit_module_header function. + (translate_pass): Moved inclusion of linux/marker.h to + mark_derived_probe_group::emit_module_header(). + * tapsets.cxx (struct be_derived_probe_group): Added empty + emit_module_header function. + (struct timer_derived_probe_group): Ditto. + (struct profile_derived_probe_group): Ditto. + (struct procfs_derived_probe_group): Ditto. + (struct hrtimer_derived_probe_group): Ditto. + (struct perfmon_derived_probe_group): Ditto. + (dwarf_derived_probe_group::emit_module_header): Moved kprobes + kernel check from emit_module_decls() to here. + (uprobe_derived_probe_group::emit_module_header): Moved uprobe + kernel check from emit_module_decls() to here. + (uprobe_derived_probe_group::emit_module_decls): Moved uprobe + kernel check to emit_module_header(). + (mark_derived_probe_group::emit_module_header): Moved marker + kernel check from emit_module_decls and translate_pass() to here. + (uprobe_derived_probe_group::emit_module_decls): Moved marker + kernel check to emit_module_header(). + 2008-04-10 Frank Ch. Eigler PR 2949. diff --git a/elaborate.h b/elaborate.h index 30bf5bce..f53f3870 100644 --- a/elaborate.h +++ b/elaborate.h @@ -150,6 +150,12 @@ struct derived_probe_group { virtual ~derived_probe_group () {} + virtual void emit_module_header (systemtap_session& s) = 0; + // The _header-generated code may assume that only basic includes + // have been generated. _header is called near the start of the + // code generation process, before the context, embedded-C code, + // etc. are generated. + virtual void emit_module_decls (systemtap_session& s) = 0; // The _decls-generated code may assume that declarations such as // the context, embedded-C code, function and probe handler bodies diff --git a/tapsets.cxx b/tapsets.cxx index ceda9015..a7f8034e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -104,6 +104,7 @@ struct be_derived_probe: public derived_probe struct be_derived_probe_group: public generic_dpg { public: + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -2068,6 +2069,7 @@ private: public: void enroll (dwarf_derived_probe* probe); + void emit_module_header (systemtap_session& s); void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -3927,17 +3929,22 @@ dwarf_derived_probe_group::enroll (dwarf_derived_probe* p) void -dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) +dwarf_derived_probe_group::emit_module_header (systemtap_session& s) { if (probes_by_module.empty()) return; - s.op->newline() << "/* ---- dwarf probes ---- */"; - - // Warn of misconfigured kernels + // Warn of misconfigured kernels s.op->newline() << "#if ! defined(CONFIG_KPROBES)"; s.op->newline() << "#error \"Need CONFIG_KPROBES!\""; s.op->newline() << "#endif"; - s.op->newline(); +} + +void +dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes_by_module.empty()) return; + + s.op->newline() << "/* ---- dwarf probes ---- */"; // Forward declare the master entry functions s.op->newline() << "static int enter_kprobe_probe (struct kprobe *inst,"; @@ -4264,6 +4271,7 @@ struct uprobe_derived_probe: public derived_probe struct uprobe_derived_probe_group: public generic_dpg { public: + void emit_module_header (systemtap_session& s); void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -4313,10 +4321,9 @@ struct uprobe_builder: public derived_probe_builder void -uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) +uprobe_derived_probe_group::emit_module_header (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "/* ---- user probes ---- */"; // If uprobes isn't in the kernel, pull it in from the runtime. s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)"; @@ -4324,6 +4331,14 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#else"; s.op->newline() << "#include \"uprobes/uprobes.h\""; s.op->newline() << "#endif"; +} + + +void +uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes.empty()) return; + s.op->newline() << "/* ---- user probes ---- */"; s.op->newline() << "struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; @@ -4442,6 +4457,7 @@ struct timer_derived_probe_group: public generic_dpg { void emit_interval (translator_output* o); public: + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -4583,6 +4599,7 @@ struct profile_derived_probe: public derived_probe struct profile_derived_probe_group: public generic_dpg { public: + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -4711,6 +4728,7 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s) } + // ------------------------------------------------------------------------ // procfs file derived probes // ------------------------------------------------------------------------ @@ -4749,6 +4767,7 @@ public: has_read_probes(false), has_write_probes(false) {} void enroll (procfs_derived_probe* probe); + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -5189,6 +5208,7 @@ procfs_builder::build(systemtap_session & sess, } + // ------------------------------------------------------------------------ // statically inserted macro-based derived probes // ------------------------------------------------------------------------ @@ -5223,6 +5243,7 @@ struct mark_derived_probe: public derived_probe struct mark_derived_probe_group: public generic_dpg { public: + void emit_module_header (systemtap_session& s); void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -5661,18 +5682,26 @@ mark_derived_probe::initialize_probe_context_vars (translator_output* o) void -mark_derived_probe_group::emit_module_decls (systemtap_session& s) +mark_derived_probe_group::emit_module_header (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "/* ---- marker probes ---- */"; - // Warn of misconfigured kernels s.op->newline() << "#if ! defined(CONFIG_MARKERS)"; s.op->newline() << "#error \"Need CONFIG_MARKERS!\""; s.op->newline() << "#endif"; + s.op->newline() << "#include "; s.op->newline(); +} + +void +mark_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes.empty()) + return; + + s.op->newline() << "/* ---- marker probes ---- */"; s.op->newline() << "struct stap_marker_probe {"; s.op->newline(1) << "const char * const name;"; @@ -5887,6 +5916,7 @@ mark_builder::build(systemtap_session & sess, } + // ------------------------------------------------------------------------ // hrtimer derived probes // ------------------------------------------------------------------------ @@ -5928,6 +5958,7 @@ struct hrtimer_derived_probe_group: public generic_dpg { void emit_interval (translator_output* o); public: + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); void emit_module_exit (systemtap_session& s); @@ -6180,6 +6211,7 @@ timer_builder::register_patterns(match_node *root) } + // ------------------------------------------------------------------------ // perfmon derived probes // ------------------------------------------------------------------------ @@ -6282,6 +6314,7 @@ public: struct perfmon_derived_probe_group: public generic_dpg { public: + void emit_module_header (systemtap_session& ) { }; void emit_module_decls (systemtap_session&) {} void emit_module_init (systemtap_session&) {} void emit_module_exit (systemtap_session&) {} diff --git a/translate.cxx b/translate.cxx index c9ec094a..ba848d43 100644 --- a/translate.cxx +++ b/translate.cxx @@ -849,6 +849,11 @@ translator_output::line () void c_unparser::emit_common_header () { + vector g = all_session_groups (*session); + for (unsigned i=0; iemit_module_header (*session); + + o->newline(); o->newline() << "typedef char string_t[MAXSTRINGLEN];"; o->newline(); o->newline() << "#define STAP_SESSION_STARTING 0"; @@ -4526,10 +4531,6 @@ translate_pass (systemtap_session& s) s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })"; s.op->newline() << "#endif"; - s.op->newline() << "#if defined(CONFIG_MARKERS)"; - s.op->newline() << "#include "; - s.op->newline() << "#endif"; - s.up->emit_common_header (); // context etc. for (unsigned i=0; i Date: Fri, 11 Apr 2008 09:57:00 -0500 Subject: 2008-04-11 David Smith * .gitignore: New file. --- testsuite/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 testsuite/.gitignore diff --git a/testsuite/.gitignore b/testsuite/.gitignore new file mode 100644 index 00000000..34a4e8d0 --- /dev/null +++ b/testsuite/.gitignore @@ -0,0 +1,4 @@ +.systemtap +site.exp +systemtap.log +systemtap.sum -- cgit From a9f3ab125303a2e89dd3c17b39f26e1d2c428fa5 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 13 Apr 2008 17:48:16 -0400 Subject: Clarify .function().call vs .function as tutorial footnote --- doc/tutorial.tex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/tutorial.tex b/doc/tutorial.tex index 58673467..3a04900b 100644 --- a/doc/tutorial.tex +++ b/doc/tutorial.tex @@ -175,8 +175,10 @@ in a source file, say \verb+net/socket.c+ in the kernel. The systemtap examines the kernel's debugging information to relate object code to source code. It works like a debugger: if you can name or place it, you can probe it. Use -\verb+kernel.function("*@net/socket.c")+ for the function entries, and -\verb+kernel.function("*@net/socket.c").return+ for the exits. Note +\verb+kernel.function("*@net/socket.c").call+ for the function +entries\footnote{Without the {\tt .call} qualifier, inlined function +instances are also probed, but they have no corresponding {\tt .return}.}, +and \verb+kernel.function("*@net/socket.c").return+ for matching exits. Note the use of wildcards in the function name part, and the subsequent \verb+@FILENAME+ part. You can also put wildcards into the file name, and even add a colon (\verb+:+) and a line number, if you want to -- cgit From f7e07777e033e580351dc6886ab7dbdddd9839fe Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 13 Apr 2008 17:50:45 -0400 Subject: runtime backtrace: stop infinite loops by checking for full print buffer 2008-04-13 Frank Ch. Eigler * print.c (_stp_pbuf_full): New function to note full print buffer. * stack-{i386,x86_64}.c: Use it in all stack-searching loops, to impose another limit against unbounded iteration. --- runtime/ChangeLog | 6 ++++++ runtime/print.c | 10 ++++++++++ runtime/stack-i386.c | 9 ++++++--- runtime/stack-x86_64.c | 3 ++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 067c5820..09a3e35d 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,9 @@ +2008-04-13 Frank Ch. Eigler + + * print.c (_stp_pbuf_full): New function to note full print buffer. + * stack-{i386,x86_64}.c: Use it in all stack-searching loops, to + impose another limit against unbounded iteration. + 2008-03-31 Martin Hunt * runtime.h (STP_USE_DWARF_UNWINDER): Define. diff --git a/runtime/print.c b/runtime/print.c index 0442ba09..4f99be7b 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -243,6 +243,16 @@ void _stp_print_char (const char c) pb->len ++; } +/** Check whether the print buffer is full. + * @return non-zero if full + */ + +static int _stp_pbuf_full (void) +{ + _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id()); + return (pb->len >= STP_BUFFER_SIZE); +} + /* This function is used when printing maps or stats. */ /* Probably belongs elsewhere, but is here for now. */ diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index 20c8eda5..78f89b0d 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -17,7 +17,8 @@ static int _stp_valid_stack_ptr(unsigned long context, unsigned long p) static void _stp_stack_print_fallback(unsigned long context, unsigned long stack, int verbose) { unsigned long addr; - while (_stp_valid_stack_ptr(context, stack)) { + while (_stp_valid_stack_ptr(context, stack) && + !_stp_pbuf_full()) { if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) { /* cannot access stack. give up. */ return; @@ -42,7 +43,8 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) unsigned long ebp = regs->ebp; #endif /* STAPCONF_X86_UNIREGS */ - while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { + while (_stp_valid_stack_ptr(context, (unsigned long)ebp) && + !_stp_pbuf_full()) { if (unlikely(_stp_read_address(addr, (unsigned long *)(ebp + 4), KERNEL_DS))) { /* cannot access stack. give up. */ return; @@ -59,7 +61,8 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) struct unwind_frame_info info; arch_unw_init_frame_info(&info, regs); - while (!arch_unw_user_mode(&info)) { + while (!arch_unw_user_mode(&info) && + !_stp_pbuf_full ()) { int ret = unwind(&info); dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); if (ret == 0) { diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index ae8e446d..9915c594 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -12,7 +12,8 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose) { unsigned long addr; - while (stack & (THREAD_SIZE - 1)) { + while (stack & (THREAD_SIZE - 1) && + !_stp_pbuf_full()) { if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) { /* cannot access stack. give up. */ return; -- cgit