summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog84
-rw-r--r--NEWS37
-rw-r--r--elaborate.cxx33
-rw-r--r--hash.cxx16
-rw-r--r--main.cxx25
-rw-r--r--runtime/ChangeLog5
-rw-r--r--runtime/loc2c-runtime.h7
-rw-r--r--runtime/task_finder.c14
-rw-r--r--runtime/task_finder_vma.c12
-rw-r--r--tapset/ChangeLog261
-rw-r--r--tapset/utrace.stp11
-rw-r--r--tapsets.cxx1137
-rw-r--r--translate.cxx11
-rw-r--r--util.cxx81
-rw-r--r--util.h2
15 files changed, 1061 insertions, 675 deletions
diff --git a/ChangeLog b/ChangeLog
index 3a8c8e6f..629b2b1a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2008-09-02 Frank Ch. Eigler <fche@elastic.org>
+
+ * tapsets.cxx (uprobe..emit_module_init): Leave dying-uprobe
+ loop as early as possible.
+
+2008-09-02 Stan Cox <scox@redhat.com>
+
+ * elaborate.cxx (add_global_var_display): Simplify token use.
+
+2008-09-02 Frank Ch. Eigler <fche@elastic.org>
+
+ PR4225.
+ * tapsets.cxx (generated stap_uprobe_change): Fix major thinko that
+ falsely triggered a slew of uprobe_unregister's for each plain
+ register.
+ (uprobe_derived_probe_group::emit_module_init): Add code to generate
+ printk's for uprobe activities, if -DDEBUG_UPROBES.
+
+2008-09-02 Frank Ch. Eigler <fche@elastic.org>
+
+ PR4225 merge.
+ * tapsets.cxx: Add prototype user-space probing support. Collateral
+ damage breaks symbol-table-only (dwarfless) probing, PR6864.
+ (setup_user, setup_kernel): Split & reorganized.
+ (class uprobe_derived_probe): Nearly all new code.
+ (base_query): Add "has_module" and "has_process" flags.
+ (dwarf_builder): Add "user_dw" map.
+ (dwarf_query::add_probe_point): Use ".dynamic" pseudo-reloc-base for
+ ET_DYN modules; ".absolute" for ET_EXEC.
+ (register_patterns): Register process(...) uprobe-based probes.
+ (task_finder_derived_probe_group::create_session_group): Let runtime
+ code assert CONFIG_UTRACE.
+ (base_query ctor, dwarf_builder::build, itrace_builder,
+ utrace_derived_probe): Use find_executable() to resolve FOO path in
+ process("FOO").
+ (utrace_derived_probe ctor): Reverse-engineer probe point.
+ * main.cxx (main): Don't override $PATH etc.
+ * util.cxx (find_executable): Reorganize, simplify, canonicalize.
+ * util.h, hash.cxx: Corresponding changes.
+
+2008-09-02 Wenji Huang <wenji.huang@oracle.com>
+
+ * tapsets.cxx (query_func_info): Disable prologue searching in
+ no-dwarf testing.
+
2008-09-01 Stan Cox <scox@redhat.com>
* elaborate.cxx (add_global_var_display): Also handle statistics.
@@ -54,7 +99,7 @@
2008-08-25 Frank Ch. Eigler <fche@elastic.org>
* Makefile.am (AUTOMAKE_OPTIONS): Add "no-dist". Remove all
- "make dist"-oriented targets and macros.
+ "make dist"-oriented targets and macros.
(rpm): Rewrite. Allow parametrization with RPMBUILDFLAGS=.
* Makefile.in: Regenerated.
* systemtap.spec: Make configuration macros at top overridable.
@@ -109,7 +154,7 @@
2008-08-20 Dave Brolley <brolley@redhat.com>
* stap-client: Ignore SIGHUP and SIGPIPE.
- (initialization): Set b_specified.:
+ (initialization): Set b_specified.:
(parse_options): Handle the -b option. Quote $stap_arg. Use process_m.
(process_m): New function.
(process_o): Set stdout_redirection to simply the filename.
@@ -250,6 +295,13 @@
2008-08-11 Frank Ch. Eigler <fche@elastic.org>
+ * tapsets.cxx (translate_final_fetch_or_store): Reject some
+ unhandleable types such as floats.
+ (dwarf_var...visit_target_symbol): Tweak logic of $$var expansion
+ to quietly skip over any $context variables that cause exceptions.
+
+2008-08-11 Frank Ch. Eigler <fche@elastic.org>
+
* tapsets.cxx (dwarf_var_expanding...visit_target_symbol):
Don't add a \n at the end of $$vars/$$parms/$$locals.
@@ -406,7 +458,7 @@
2008-08-04 Stan Cox <scox@redhat.com>
- * tapsets.cxx (dwarf_var_expanding_copy_visitor::visit_target_symbol):
+ * tapsets.cxx (dwarf_var_expanding_copy_visitor::visit_target_symbol):
Add support for $$vars, $$parms, and $$locals.
* stapprobes.5.in: Likewise.
* doc/langref.tex: Likewise.
@@ -585,12 +637,12 @@
which may be unrelocatable.
2008-07-11 Frank Ch. Eigler <fche@elastic.org>
-
+
* hash.cxx (find_hash): Mix in -d MODULE names.
2008-07-10 Frank Ch. Eigler <fche@elastic.org>
- * main.cxx (main): If "-k" (save temp directory) was supplied,
+ * main.cxx (main): If "-k" (save temp directory) was supplied,
disable caching.
2008-07-10 Frank Ch. Eigler <fche@elastic.org>
@@ -877,14 +929,14 @@
* tapsets.cxx (dwarf_assert, dwfl_assert): Move to
dwarf_wrappers.h.
(iterate_over_srcfile_lines, has_single_line_record,
- query_srcfile_line): Use dwarf_line_t wrapper.
+ query_srcfile_line): Use dwarf_line_t wrapper.
(die_has_pc): Take a reference to a Dwarf_Die instead of a
pointer. Clean up use of dwfl_assert.
(query_cu): Check that statement raw address matches the beginning
of a statement record.
* elaborate.h: Include iosfwd instead of iostream.
(literal_map_t, resolve_prologue_endings,): New typedef.
-
+
2008-06-10 Jim Keniston <jkenisto@us.ibm.com>
@@ -918,7 +970,7 @@
(lexer::scan): Ditto. Interpret "$#" as the argc value in all
cases.
* parse.h: Corresponding decl changes.
-
+
2008-06-10 Frank Ch. Eigler <fche@elastic.org>
PR 6470
@@ -951,8 +1003,8 @@
2008-06-06 Stan Cox <scox@redhat.com>
- * tapsets.cxx (dwflpp::iterate_over_srcfile_lines):
- Add parameter line_type_relative.
+ * tapsets.cxx (dwflpp::iterate_over_srcfile_lines):
+ Add parameter line_type_relative.
(enum line_t): New.
(dwarf_query::line_type): New.
(dwarf_query::parse_function_spec): Set line_type.
@@ -1084,7 +1136,7 @@
* tapsets.cxx: Convert .funcname to funcname when adding it
to our symbol table. Accept all weak symbols except those
that map to sys_ni_syscall.
-
+
2008-05-23 Srinivasa DS <srinivasa@in.ibm.com>
PR 6429: Inerim fix to avoid compilation error of systemtap module
* runtime/transport/symbols.c: added definitions of struct
@@ -1116,7 +1168,7 @@
* elaborate.cxx (dead_assignment_remover::visit_binary_expression): New.
(dead_assignment_remover::visit_assignment): Allow rhs simplification.
-
+
2008-05-20 Tim Moore <timoore@redhat.com>
* configure.ac: Check for tr1/unordered_map header.
@@ -1179,7 +1231,7 @@
x86_64 remains in regs.c.
* tapset/{i686,x86_64}/registers.stp: Moved register-lookup
code from runtime/regs.c to here.
-
+
2008-05-12 Jim Keniston <jkenisto@us.ibm.com>
(2008-05-06 in dwarfless branch)
@@ -1629,7 +1681,7 @@
2008-02-25 Frank Ch. Eigler <fche@elastic.org>
PR5792.
- * parse.cxx (eval_pp_conditional): Support wildcards in
+ * parse.cxx (eval_pp_conditional): Support wildcards in
%( kernel_v/kernel_vr/arch ==/!= "*foo?" %) operands.
* NEWS, stap.1.in: Document this.
@@ -1661,7 +1713,7 @@
(register_standard_tapsets): Added new 'format' marker probe
optional parameter.
* stapprobes.5.in (parts): Documented new "format" probe
- component.
+ component.
2008-02-19 Roland McGrath <roland@redhat.com>
@@ -1930,7 +1982,7 @@
* configure: Regenerated.
2008-01-17 Srinivasa DS <srinivasa@in.ibm.com>
-
+
PR 5483
* tapsets.cxx : Possible fix for making systemtap compatible with
the elfutils-0.131
diff --git a/NEWS b/NEWS
index fec89559..be56757d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,30 @@
* What's new
+- All user-space-related probes support $PATH-resolved executable
+ names, so
+
+ probe process("ls").syscall {}
+ probe process("./a.out").syscall {}
+
+ work now, instead of just
+
+ probe process("/bin/ls").syscall {}
+ probe process("/my/directory/a.out").syscall {}
+
+- Prototype symbolic user-space probing support:
+
+ # stap -e 'probe process("ls").function("*").call {
+ log (probefunc()." ".$$parms)
+ }' \
+ -c 'ls -l'
+
+ This requires:
+ - debugging information for the named program
+ - a version of utrace in the kernel that is compatible with the "uprobes"
+ kernel module prototype. This includes RHEL5 and older Fedora, but not
+ yet current lkml-track utrace; a "pass 4a"-time build failure means
+ your system cannot use this yet.
+
- Prototype systemtap client and compile server are now available.
These allow you to compile a systemtap module on a host other than
the one which it will be run, providing the client and server
@@ -10,10 +35,10 @@
was specified. See stap-server(8) for more details.
- Global variables which are written to but never read are now
- automatically displayed when the session does a shutdown. For example:
+ automatically displayed when the session does a shutdown. For example:
- global running_tasks
- probe timer.profile {running_tasks[pid(),tid()] = execname()}
+ global running_tasks
+ probe timer.profile {running_tasks[pid(),tid()] = execname()}
probe timer.ms(8000) {exit()}
- A formatted string representation of the variables, parameters, or local
@@ -109,7 +134,7 @@
printf ("%*d", four, two) // prints <space><space><space>2
- Preprocessor conditional expressions can now include wildcard style
- matches on kernel versions.
+ matches on kernel versions.
%( kernel_vr != "*xen" %? foo %: bar %)
- Prototype support for user-space probing is showing some progress.
@@ -303,12 +328,12 @@
handlers are invoked, as a safety improvement.
- Add an optional numeric parameter for begin/end probe specifications,
- to order their execution.
+ to order their execution.
probe begin(10) { } /* comes after */ probe begin(-10) {}
- Add an optional array size declaration, which is handy for very small
or very large ones.
- global little[5], big[20000]
+ global little[5], big[20000]
- Include some example scripts along with the documentation.
diff --git a/elaborate.cxx b/elaborate.cxx
index cfbe1392..44b6e24f 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1172,10 +1172,7 @@ void add_global_var_display (systemtap_session& s)
block *b = new block;
pl->components.push_back (c);
- token* p_tok = new token;
- p_tok->type = tok_identifier;
- p_tok->content = "probe";
- p->tok = p_tok;
+ p->tok = l->tok;
p->locations.push_back (pl);
print_tok->type = tok_identifier;
print_tok->content = "printf";
@@ -1211,13 +1208,9 @@ void add_global_var_display (systemtap_session& s)
else // Array
{
int idx_count = l->index_types.size();
- token* idx_tok[idx_count];
symbol* idx_sym[idx_count];
vardecl* idx_v[idx_count];
// Create a foreach loop
- token* fe_tok = new token;
- fe_tok->type = tok_identifier;
- fe_tok->content = "foreach";
foreach_loop* fe = new foreach_loop;
fe->sort_direction = 0;
fe->limit = NULL;
@@ -1225,19 +1218,16 @@ void add_global_var_display (systemtap_session& s)
// Create indices for the foreach loop
for (int i=0; i < idx_count; i++)
{
- idx_tok[i] = new token;
- idx_tok[i]->type = tok_identifier;
char *idx_name;
if (asprintf (&idx_name, "idx%d", i) < 0)
return;
- idx_tok[i]->content = idx_name;
idx_sym[i] = new symbol;
- idx_sym[i]->tok = idx_tok[i];
idx_sym[i]->name = idx_name;
+ idx_sym[i]->tok = l->tok;
idx_v[i] = new vardecl;
idx_v[i]->name = idx_name;
- idx_v[i]->tok = idx_tok[i];
idx_v[i]->type = l->index_types[i];
+ idx_v[i]->tok = l->tok;
idx_sym[i]->referent = idx_v[i];
fe->indexes.push_back (idx_sym[i]);
}
@@ -1274,25 +1264,22 @@ void add_global_var_display (systemtap_session& s)
if (l->type == pe_stats)
{
struct stat_op* so [5];
- token* so_tok [5];
-
- for (unsigned sti = 0; sti < (sizeof(so_tok)/sizeof(token*)); sti++)
- {
- so_tok[sti] = new token;
- so_tok[sti]->type = tok_identifier;
- }
const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
- for (unsigned si = 0; si < (sizeof(so_tok)/sizeof(token*)); si++)
+ for (unsigned si = 0;
+ si < (sizeof(so)/sizeof(struct stat_op*));
+ si++)
{
so[si]= new stat_op;
so[si]->ctype = stypes[si];
so[si]->type = pe_long;
so[si]->stat = ai;
- so[si]->tok = so_tok[si];
+ so[si]->tok = l->tok;
}
ai->type = pe_stats;
- for (unsigned si = 0; si < (sizeof(so_tok)/sizeof(token*)); si++)
+ for (unsigned si = 0;
+ si < (sizeof(so)/sizeof(struct stat_op*));
+ si++)
pf->args.push_back(so[si]);
}
else
diff --git a/hash.cxx b/hash.cxx
index ef02c8f1..45039391 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -126,16 +126,14 @@ find_hash (systemtap_session& s, const string& script)
h.add(s.runtime_path);
// Hash compiler path, size, and mtime. We're just going to assume
- // we'll be using gcc, which should be correct most of the time.
- string gcc_path;
- if (find_executable("gcc", gcc_path))
+ // we'll be using gcc. XXX: getting kbuild to spit out out would be
+ // better.
+ string gcc_path = find_executable ("gcc");
+ if (stat(gcc_path.c_str(), &st) == 0)
{
- if (stat(gcc_path.c_str(), &st) == 0)
- {
- h.add(gcc_path);
- h.add(st.st_size);
- h.add(st.st_mtime);
- }
+ h.add(gcc_path);
+ h.add(st.st_size);
+ h.add(st.st_mtime);
}
// Hash the systemtap size and mtime. We could use VERSION/DATE,
diff --git a/main.cxx b/main.cxx
index 51252e61..11244d8d 100644
--- a/main.cxx
+++ b/main.cxx
@@ -709,25 +709,11 @@ main (int argc, char * const argv [])
int rc = 0;
- // override PATH and LC_ALL
- const char *path = "/bin:/sbin:/usr/bin:/usr/sbin";
- rc = setenv("PATH", path, 1) || setenv("LC_ALL", "C", 1);
- if (rc)
- {
- const char* e = strerror (errno);
- cerr << "setenv (\"PATH=" << path << "\" + \"LC_ALL=C\"): "
- << e << endl;
- }
-
- // Get rid of a few standard environment variables (which might
- // cause us to do unintended things).
- rc = unsetenv("IFS") || unsetenv("CDPATH") || unsetenv("ENV")
- || unsetenv("BASH_ENV");
- if (rc)
- {
- const char* e = strerror (errno);
- cerr << "unsetenv failed: " << e << endl;
- }
+ // For PR1477, we used to override $PATH and $LC_ALL and other stuff
+ // here. We seem to use complete pathnames in
+ // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
+ // it interferes with util.cxx:find_executable(), used for $PATH
+ // resolution.
s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
@@ -1006,6 +992,7 @@ main (int argc, char * const argv [])
if (rc || s.last_pass == 3 || pending_interrupts) goto cleanup;
// PASS 4: COMPILATION
+
times (& tms_before);
gettimeofday (&tv_before, NULL);
rc = compile_pass (s);
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index b7e44a0f..e02c5f0b 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,8 @@
+2008-09-01 Frank Ch. Eigler <fche@elastic.org>
+
+ * task_finder.c: Move CONFIG_UTRACE assertion here.
+ * task_finder_vma.c (__stp_tf_add_vma): Make printk conditional.
+
2008-08-29 David Smith <dsmith@redhat.com>
* task_finder.c (__stp_utrace_attach_match_filename): Don't call
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index 215676ee..1247da51 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -113,16 +113,13 @@
kernel mode, it is not saved in the trap frame (struct pt_regs).
The `esp' (and `xss') fields are valid only for a user-mode trap.
For a kernel mode trap, the interrupted state's esp is actually an
- address inside where the `struct pt_regs' on the kernel trap stack points.
-
- For now we assume all traps are from kprobes in kernel-mode code.
- For extra paranoia, could do BUG_ON((regs->xcs & 3) == 3). */
+ address inside where the `struct pt_regs' on the kernel trap stack points. */
#define dwarf_register_0(regs) regs->eax
#define dwarf_register_1(regs) regs->ecx
#define dwarf_register_2(regs) regs->edx
#define dwarf_register_3(regs) regs->ebx
-#define dwarf_register_4(regs) ((long) &regs->esp)
+#define dwarf_register_4(regs) (user_mode(regs) ? regs->esp : (long)&regs->esp)
#define dwarf_register_5(regs) regs->ebp
#define dwarf_register_6(regs) regs->esi
#define dwarf_register_7(regs) regs->edi
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index f1c2c41b..9c0dd55b 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -1,5 +1,15 @@
+#ifndef TASK_FINDER_C
+#define TASK_FINDER_C
+
+#if ! defined(CONFIG_UTRACE)
+#error "Need CONFIG_UTRACE!"
+#endif
+
+#include <linux/utrace.h>
#include <linux/list.h>
#include <linux/binfmts.h>
+#include <linux/mount.h>
+
#include "syscall.h"
#include "utrace_compatibility.h"
#include "task_finder_vma.c"
@@ -1110,6 +1120,7 @@ stap_start_task_finder(void)
struct task_struct *grp, *tsk;
char *mmpath_buf;
+ debug_task_finder_report();
mmpath_buf = _stp_kmalloc(PATH_MAX);
if (mmpath_buf == NULL) {
_stp_error("Unable to allocate space for path");
@@ -1217,3 +1228,6 @@ stap_stop_task_finder(void)
debug_task_finder_report();
atomic_set(&__stp_task_finder_state, __STP_TF_STOPPED);
}
+
+
+#endif /* TASK_FINDER_C */
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index 9d43e36c..8c60175e 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -133,11 +133,13 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
&& addr == entry->addr) {
- printk(KERN_NOTICE
- "vma (pid: %d, vm_start: 0x%lx) present?\n",
- tsk->pid, vma->vm_start);
- mutex_unlock(&__stp_tf_vma_mutex);
- return -EBUSY; /* Already there */
+#ifdef DEBUG_TASK_FINDER_VMA
+ printk(KERN_NOTICE
+ "vma (pid: %d, vm_start: 0x%lx) present?\n",
+ tsk->pid, vma->vm_start);
+#endif
+ mutex_unlock(&__stp_tf_vma_mutex);
+ return -EBUSY; /* Already there */
}
}
diff --git a/tapset/ChangeLog b/tapset/ChangeLog
index 61976ee0..39b6b93b 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,8 @@
+2008-09-01 Frank Ch. Eigler <fche@elastic.org>
+
+ PR4225 merge.
+ * utrace.stp: New file, for use by utrace $var expansions.
+
2008-09-01 Zhaolei <zhaolei@cn.fujitsu.com>
* nfs_proc.stp: Fix memory access error in nfs.proc.read_setup,
nfs.proc.write_setup and nfs.proc.commit_setup.
@@ -54,7 +59,7 @@
2008-06-20 wcohen <wcohen@redhat.com>
* dev.stp: New.
-
+
2008-06-19 Zhaolei <zhaolei@cn.fujitsu.com>
* aux_syscalls.stp: Output unknown bits in _stp_lookup_or_str.
@@ -175,9 +180,9 @@
PR 5231
* ioblock.stp (ioblock.end): Set bytes_done depending on kernel
version.
-
+
2008-04-29 Frank Ch. Eigler <fche@elastic.org>
-
+
PR 6466
* tcp.stp (tcp_sockstate_str, tcp_sockopt_str): Initialize
number->string lookup tables here, instead of "probe begin(-1)"
@@ -214,7 +219,7 @@
register unification
2008-02-28 Will Cohen <wcohen@redhat.com>
-
+
PR433780
* errno.stp (returnstr): Handle unified i386/x86_64 reg names.
@@ -224,7 +229,7 @@
on xen kernel.
2008-01-25 Will Cohen <wcohen@redhat.com>
-
+
PR5554
* syscalls.stp (__is_user_regs): Modify to work with older kernels.
@@ -282,7 +287,7 @@
(kexec_load): Ditto.
(mbind): Ditto.
(move_pages): Ditto.
-
+
2007-12-17 Zhaolei <zhaolei@cn.fujitsu.com>
From Yang Zhiguo <yzgcsu@cn.fujitsu.com>
@@ -324,13 +329,13 @@
2007-11-12 Martin Hunt <hunt@redhat.com>
- * logging.stp (print_char): Remove. Now implemented by
+ * logging.stp (print_char): Remove. Now implemented by
stap.
(log): Add a comment that it is deprecated.
-
+
2007-11-12 Martin Hunt <hunt@redhat.com>
-
- * syscalls2.stp (sys_remap_file_pages: : Change kernel
+
+ * syscalls2.stp (sys_remap_file_pages: : Change kernel
version check to >= 2.6.24.
2007-11-8 Zhaolei <zhaolei@cn.fujitsu.com>
@@ -437,14 +442,14 @@
sa_restorer field for IA64.
2007-10-09 Martin Hunt <hunt@redhat.com>
-
+
* syscalls2.stp (sys_signal): Call
_sighandler_str().
* aux_syscalls.stp (_stp_sigset_str): Don't
include SIG_0.
(_sighandler_str): New.
-
+
2007-10-09 Zhaolei <zhaolei@cn.fujitsu.com>
* queue_stats.stp (qsq_start): Add destruction for qs_utime.
@@ -462,16 +467,16 @@
* syscalls2.stp (rt_sigaction, sigaction): Call
_struct_sigaction_u().
-
- * aux_syscalls.stp (_struct_timeval): Removed. No longer
- necessary now that we have structure access in scripts.
+
+ * aux_syscalls.stp (_struct_timeval): Removed. No longer
+ necessary now that we have structure access in scripts.
(_struct_timespec): Ditto.
(_struct_itimerval): Ditto.
(_struct_timezone_u): Remove random CATCH_DEREF_FAULT()
line.
(_stp_sigset_str): New.
(_struct_sigaction_u): New.
-
+
2007-10-04 Frank Ch. Eigler <fche@elastic.org>
* inet.stp: New tapset for htonl and friends.
@@ -493,7 +498,7 @@
2007-10-01 Martin Hunt <hunt@redhat.com>
- * aux_syscalls.stp (_str_lookup_str): Print unmatched
+ * aux_syscalls.stp (_str_lookup_str): Print unmatched
values in hex.
2007-10-01 Zhaolei <zhaolei@cn.fujitsu.com>
@@ -513,7 +518,7 @@
(_shmat_flags_str): Ditto.
(_at_flag_str): Ditto.
(get_mmap_args): Complete rewrite for safety and correctness.
-
+
2007-09-27 Wenji Huang <wenji.huang@oracle.com>
* rpc.stp (clones_from_clnt, tasks_from_clnt): Fix for kernel >= 2.6.22.
@@ -554,7 +559,7 @@
Added __page_index() to work around problem dereferencing unions
in stap language.
-
+
Made generic.fop.sendfile conditional on kernel <= 2.6.22.
generic_file_sendfile() was removed in 2.6.23.
@@ -619,7 +624,7 @@
2007-09-24 Frank Ch. Eigler <fche@elastic.org>
- * aux_syscalls.stp: Add missing CATCH_DEREF_FAULT()s.
+ * aux_syscalls.stp: Add missing CATCH_DEREF_FAULT()s.
2007-09-24 Frank Ch. Eigler <fche@elastic.org>
@@ -772,21 +777,21 @@
* syscalls2.stp (sys_tee.return): Make optional
2007-08-23 Martin Hunt <hunt@redhat.com>
-
+
* aux_syscalls.stp (_struct_compat_timeval_u): Fix
array reference.
(_struct_compat_timespec_u): Cast args to long.
2007-08-23 Martin Hunt <hunt@redhat.com>
-
+
From Cai Fei <caifei@cn.fujitsu.com>
* aux_syscalls.stp (_waitid_opt_str): New.
(_wait4_opt_str): Just handle wait4 options.
* syscalls2.stp (sys_waitid): Use _waitid_opt_str.
-
+
2007-08-23 Wenji Huang <wenji.huang@oracle.com>
- * rpc.stp (sunrpc.svc.process, sunrpc.svc.recv): Modify evaluating
+ * rpc.stp (sunrpc.svc.process, sunrpc.svc.recv): Modify evaluating
sv_name,sv_prog,sv_nrthreads in kernel>=2.6.19.
(sunrpc.sched.delay,sunrpc.sched.delay): Fix typo.
(sunrpc.*.return): Change name by adding "return".
@@ -809,49 +814,49 @@
* syscalls.stp (compat_sys_epoll_ctl): New.
(compat_sys_epoll_wait): New.
(sys_epoll_pwait): New.
- (compat_sys_epoll_pwait): New.
+ (compat_sys_epoll_pwait): New.
(compat_sys_keyctl): New.
(compat_sys_mq_open): New.
- (compat_sys_futex): New.
+ (compat_sys_futex): New.
(compat_sys_mq_timedsend): New.
(compat_sys_mq_timedreceive): New.
(compat_sys_mq_notify): New.
(compat_sys_mq_getsetattr): New.
(init_module): Make optional and quote args.
(sys_eventfd): New.
-
+
* syscalls2.stp (sys_splice): New.
(sys_vmsplice): New.
- (compat_sys_vmsplice): New.
+ (compat_sys_vmsplice): New.
(sys_tee): New.
- (sys_signalfd): New.
- (compat_sys_signalfd): New.
+ (sys_signalfd): New.
+ (compat_sys_signalfd): New.
(sys_timerfd): New.
(compat_sys_timerfd): New.
(old32_readdir): New.
-
+
2007-08-22 Martin Hunt <hunt@redhat.com>
-
+
* aux_syscalls.stp (_utimensat_flag_str): New.
(_dfd_str): New.
(_struct_timeval2_u): Deleted.
(_struct_timeval_u): Take a number of structs to decode.
- (_struct_compat_timeval2_u): Deleted
- (_struct_compat_timeval_u): Take a number of structs to decode.
+ (_struct_compat_timeval2_u): Deleted
+ (_struct_compat_timeval_u): Take a number of structs to decode.
(_struct_timespec_u): Take a number of structs to decode.
Recognize UTIME_NOW and UTIME_OMIT.
(_struct_compat_timespec_u): Ditto.
-
+
* syscalls.stp (compat_sys_old_getrlimit): Removed.
(sys_migrate_pages): New.
(sys_move_pages): New.
* syscalls2.stp (compat_sys_sigprocmask): Removed. Calls
sys_sigprocmask.
- (compat_sys_sysinfo): New.
+ (compat_sys_sysinfo): New.
(compat_sys_rt_sigtimedwait): New.
(sys_utimensat, compat_sys_utimensat): New.
-
+
* ppc64/syscalls.stp (compat_sys_sigpending): Removed.
Calls sys_ func.
(compat_sys_setrlimit): Ditto.
@@ -860,11 +865,11 @@
(compat_sys_getrusage): Ditto.
(compat_sys_wait4): Ditto.
(compat_sys_sched_setaffinity): Ditto.
- (compat_sys_sched_getaffinity): Ditto.
-
+ (compat_sys_sched_getaffinity): Ditto.
+
2007-08-22 Wenji Huang <wenji.huang@oracle.com>
- * nfsd.stp (nfsd.proc?.*): Modify evaluating client_ip
+ * nfsd.stp (nfsd.proc?.*): Modify evaluating client_ip
with function addr_from_rqst to make it compatible in kernel>=2.6.19
(nfsd.proc4.compound,nfsd.read,nfsd.write): Fix typo.
(nfsd.unlink): Fix reference to variable iap.
@@ -907,7 +912,7 @@
* nfs.stp (nfs.fop.aio_read, nfs.fop.aio_write): Modify evaluating count.
(__iov_length): New function.
(nfs.fop.sendfile, nfs.aop.set_page_dirty, nfs.aop.prepare_write,
- nfs.aop.release_page): Fix typo.
+ nfs.aop.release_page): Fix typo.
2007-08-17 Martin Hunt <hunt@redhat.com>
From Lai Jiangshan <laijs@cn.fujitsu.com>
@@ -932,10 +937,10 @@
From zhaolei@cn.fujitsu.com
Remove PF_UNIX. PF_LOCAL is correct.
-
-2007-08-16 Martin Hunt <hunt@redhat.com>
- * aux_syscalls.stp (__get_argv): Add parameter to
+2007-08-16 Martin Hunt <hunt@redhat.com>
+
+ * aux_syscalls.stp (__get_argv): Add parameter to
optionally skip the first argv (argv[0]).
(__get_compat_argv): Ditto.
@@ -943,8 +948,8 @@
For argstr use filename plus argv starting at [1].
(compat_execve): Ditto.
* ppc64/syscalls.stp (sys32_exevve): Ditto.
-
- From Cai Fei <caifei@cn.fujitsu.com>
+
+ From Cai Fei <caifei@cn.fujitsu.com>
* syscalls.stp (sts_getpgid): Add pid arg.
2007-08-16 Wenji Huang <wenji.huang@oracle.com>
@@ -965,7 +970,7 @@
* aux_syscalls.stp (get_mmap_args): Moved here.
* syscalls.stp: Add sys32_alarm.
* syscalls2.stp: Add sys32_uname.
-
+
2007-08-15 Frank Ch. Eigler <fche@elastic.org>
* context.stp (cpuid, cpu): Use smp_processor_id().
@@ -1001,7 +1006,7 @@
* tapset/syscalls.stp (syscall.compat_execve,
syscall.compat_execve.return):
- * tapset/syscalls2.stp (syscall.compat_sys_semtimedop,
+ * tapset/syscalls2.stp (syscall.compat_sys_semtimedop,
syscall.compat_sys_semtimedop.return):
* tapset/i686/syscalls.stp (syscall.set_zone_reclaim,
syscall.set_zone_reclaim.return): Make optional.
@@ -1018,13 +1023,13 @@
2007-07-31 Martin Hunt <hunt@redhat.com>
* syscalls*: Move sys32_sysctl to arch dirs.
-
+
2007-07-31 Martin Hunt <hunt@redhat.com>
* syscalls.stp (clock_nanosleep): Fix flags string.
* syscalls2.stp: Fix typo.
-2007-07-31 Martin Hunt <hunt@redhat.com>
+2007-07-31 Martin Hunt <hunt@redhat.com>
* */syscalls.stp: Added mmap functions.
Continued moving common compatibility functions to
@@ -1056,9 +1061,9 @@
(semctl): Make optional.
(compat_sys_semctl): New.
(semget): Make optional.
- (semop): Make optional.
- (semtimedop): Make optional.
- (compat_sys_semtimedop): New.
+ (semop): Make optional.
+ (semtimedop): Make optional.
+ (compat_sys_semtimedop): New.
(send): Make optional.
(sendmsg): Make optional.
(compat_sys_sendmsg): New.
@@ -1078,7 +1083,7 @@
(sysctl): Add probe on sys32.
2007-07-31 Frank Ch. Eigler <fche@elastic.org>
-
+
PR 4793
* ppc64/syscalls.stp: Remove duplicate sys_request_key{,.return}
aliases.
@@ -1109,7 +1114,7 @@
2007-07-16 Martin Hunt <hunt@redhat.com>
(compat_sys_io_submit): Fix typo.
-2007-07-16 Martin Hunt <hunt@redhat.com>
+2007-07-16 Martin Hunt <hunt@redhat.com>
* syscalls.stp (compat_sys_fcntl64, compat_sys_fcntl): Add.
(compat_sys_fstatfs64): Add.
(compat_sys_getdents, compat_sys_getdents64): Add.
@@ -1131,9 +1136,9 @@
(sys_select): Don't try to print fd_sets.
(compat_sys_select): Add.
(compat_sys_statfs64): Add.
-
+
* ppc/syscalls.stp: Remove duplicated probes.
-
+
* aux_syscalls.stp (_nfsctl_cmd_str): New.
(_fd_set_u): Removed. Not used.
@@ -1145,10 +1150,10 @@
2007-07-10 Martin Hunt <hunt@redhat.com>
- * aux_syscalls.stp (_struct_compat_timeval2_u):
+ * aux_syscalls.stp (_struct_compat_timeval2_u):
Fixes.
-2007-07-10 Martin Hunt <hunt@redhat.com>
+2007-07-10 Martin Hunt <hunt@redhat.com>
* syscall*.stp: Major reorganization work.
* aux_syscalls.stp (_sigprocmask_how_str): Rewrite
in C so real arch-dependent header files
@@ -1158,7 +1163,7 @@
2007-07-09 Martin Hunt <hunt@redhat.com>
* syscalls2.stp (compat_sys_settimeofday): New.
-2007-07-09 Martin Hunt <hunt@redhat.com>
+2007-07-09 Martin Hunt <hunt@redhat.com>
* syscalls2.stp (compat_sys_utimes): New.
* ppc64/syscalls.stp (compat_sys_utimes): Removed.
@@ -1185,21 +1190,21 @@
2007-06-15 Martin Hunt <hunt@redhat.com>
- * syscalls.stp: Add sys_fcntl64, sys_oabi_fstat64,
+ * syscalls.stp: Add sys_fcntl64, sys_oabi_fstat64,
sys_oabi_lstat64.
* syscalls2.stp: Fix sys_send. Add sys_sendfile64.
* errno.stp: Add arm support.
2007-06-14 Mike Mason <mmlnx@us.ibm.com>
- * socket.stp: removed extra assignment to "size" in
+ * socket.stp: removed extra assignment to "size" in
socket.aio_write.return
2007-06-07 Martin Hunt <hunt@redhat.com>
Fallout from PR 3331 fix. Sometimes glibc and the
kernel disagree about signed vs unsigned.
* aux_syscalls.stp: Rename __uid() to __int32().
- * syscalls.stp: Change syscall.chown, syscall.fchown,
+ * syscalls.stp: Change syscall.chown, syscall.fchown,
syscall.lchown, and syscall.lseek to use __int32().
* syscalls2.stp: Change syscall.setregid, syscall.resgid,
syscall.resuid, and syscall.setreuid to use __int32().
@@ -1214,16 +1219,16 @@
* syscalls2.stp: Make optional sys_nice, sys_rt_sigreturn,
sys_signal, sys_sigprocmask, sys_utime
(syscall.old_getrlimit): Moved into syscall.getrlimit.
-
+
2007-05-16 Will Cohen <wcohen@redhat.com>
PR 4471
* syscall2.stp: Correct sys_pipe function args for ia64.
-
+
2007-05-16 Will Cohen <wcohen@redhat.com>
PR 4510
* scheduler.stp: Correct function argument.
-
+
2007-05-09 Martin Hunt <hunt@redhat.com>
* syscalls2.stp: Added compat_sys_pause to syscall.pause.
@@ -1334,7 +1339,7 @@
(backtrace): Just use _stp_stack_snprint().
(print_stack): Use new _stp_print* functions.
(probefunc): Use _stp_symbol_snprint.
-
+
2007-01-26 Josh Stone <joshua.i.stone@intel.com>
* vfs.stp (ppos_pos): Change deref() to kread() so i686 passes.
@@ -1373,14 +1378,14 @@
2007-01-12 Mike Mason <mmlnx@us.ibm.com>
* x86_64/syscalls.stp: added ? to request_key aliases
- to prevent syscall.* failures on some kernels
+ to prevent syscall.* failures on some kernels
2006-12-29 Li Guanglei <guanglei@cn.ibm.com>
From Gui Jian <guij@cn.ibm.com>
- * ioscheduler.stp, nfsd.stp, nfs.stp, nfs_proc.stp,
+ * ioscheduler.stp, nfsd.stp, nfs.stp, nfs_proc.stp,
rpc.stp, vfs.stp: patch for 2.6.19 kernel
-
+
2006-12-18 Frank Ch. Eigler <fche@elastic.org>
* vfs.stp (ppos_pos): Protect contents with deref(), though
@@ -1395,13 +1400,13 @@
From Gui Jian <guij@cn.ibm.com>
* nfs.stp, nfs_proc.stp, rpc.stp: patch for 2.6.9 kernel
-
+
2006-11-29 Li Guanglei <guanglei@cn.ibm.com>
From Gui Jian <guij@cn.ibm.com>
- * scheduler.stp, vfs.stp: made idle_balance and
+ * scheduler.stp, vfs.stp: made idle_balance and
buffer_migrate_page optinal.
-
+
2006-11-20 Frank Ch. Eigler <fche@elastic.org>
* context.stp (caller_addr): Declare return type.
@@ -1439,7 +1444,7 @@
(stack_used): New.
(stack_unused): New.
(called_addr): New.
- (caller): New.
+ (caller): New.
2006-10-12 Li Guanglei <guanglei@cn.ibm.com>
* ioscheduler.stp: bugfix to avoid refer to NULL pointer
@@ -1467,7 +1472,7 @@
Use gettimeofday_ns as the base unit.
2006-09-19 Li Guanglei <guanglei@cn.ibm.com>
-
+
From Gui Jian <guijian@cn.ibm.com>
* rpc.stp: Some changes and more comments of RPC tapset
@@ -1478,48 +1483,48 @@
* string.stp: Fix docs.
2006-09-12 Li Guanglei <guanglei@cn.ibm.com>
-
+
From Li Xuepeng <xuepengl@cn.ibm.com>
- * nfsd.stp, nfs_proc.stp, nfs.stp:
+ * nfsd.stp, nfs_proc.stp, nfs.stp:
Change NFS file identifier. Change NFS version data type
- from String to INT. Add version variable to nfs_open
+ from String to INT. Add version variable to nfs_open
and nfs_release.
-
+
2006-09-11 Li Guanglei <guanglei@cn.ibm.com>
-
+
From Gui Jian(guijian@cn.ibm.com>
* rpc.stp: tapsets for RPC activities.
-
+
2006-08-30 Li Guanglei <guanglei@cn.ibm.com>
- * signal.stp: some changes to arguments and comments
+ * signal.stp: some changes to arguments and comments
of signal tapset
-
+
2006-08-25 Li Guanglei <guanglei@cn.ibm.com>
From Li Xuepeng:
* vfs.stp,nfsd.stp,nfs.stp: bug fixes and more error checking
-
+
2006-08-23 Li Guanglei <guanglei@cn.ibm.com>
* vfs.stp: New tapset from Thomas Zanussi(trz@us.ibm.com) to probe
vfs layer activities.
* nfs.stp: New tapset from Li Xuepeng(xuepengl@cn.ibm.com) to probe
nfs file operations and nfs address space operations on client side.
- * nfs_proc.stp: New tapset from Li Xuepeng to probe some nfs RPC
+ * nfs_proc.stp: New tapset from Li Xuepeng to probe some nfs RPC
procedure stub functions on client side.
- * nfsd.stp: New tapset from Li Xuepeng to probe nfs server side
- activities, including some RPC procedure stub functions, nfsd
+ * nfsd.stp: New tapset from Li Xuepeng to probe nfs server side
+ activities, including some RPC procedure stub functions, nfsd
dispatch routine, and nfsd_* functions
-
+
2006-08-22 Li Guanglei <guanglei@cn.ibm.com>
* signal.stp: More variables for signal.do_action and
signal.procmask. New function of get_sigset(). Minor
changes to naming of signal.pend and its comments
-
+
2006-08-21 Martin Hunt <hunt@redhat.com>
* string.stp (substr): Rewrite. Make the 3rd parameter
@@ -1528,30 +1533,30 @@
2006-08-17 Josh Stone <joshua.i.stone@intel.com>
* signal.stp: Changes on behalf of Manoj S Pattabhiraman:
- 1. As per the suggestions, i have removed the argstr from the
+ 1. As per the suggestions, i have removed the argstr from the
probe points.
- 2. Added some checks to find whether the signals generated are
+ 2. Added some checks to find whether the signals generated are
USER or Kernel Mode in signal_handle probe.
2006-08-17 Li Guanglei <guanglei@cn.ibm.com>
* signal.stp: update signal tapsets based on the discussion
with Josh Stone on mailinglist:
- 1. Added "send2queue" and "name" variable for signal.send.part*
- 2. Added signal.send.return probe alias
+ 1. Added "send2queue" and "name" variable for signal.send.part*
+ 2. Added signal.send.return probe alias
3. Added signal.checkperm and signal.checkperm.return probe alias
4. Commented out signal.handle_stop
5. Alias all signal syscalls to syscall tapsets.
2006-08-15 Thang Nguyen <thang.p.nguyen@intel.com>
- * ioblock.stp: Added safety checks for __bio_ino() and
- __bio_start_sect().
+ * ioblock.stp: Added safety checks for __bio_ino() and
+ __bio_start_sect().
2006-08-09 Thang Nguyen <thang.p.nguyen@intel.com>
* ioblock.stp: Merged io.stp from Tom Zanussi (IBM) into existing
- ioblock.stp. Removed/Renamed duplicate variables and probes.
+ ioblock.stp. Removed/Renamed duplicate variables and probes.
2006-08-09 Josh Stone <joshua.i.stone@intel.com>
@@ -1582,31 +1587,31 @@
* return.stp: Removed. Use $return instead.
2006-07-17 Tom Zanussi <zanussi@us.ibm.com>
-
+
* ioblock.stp: add null bi_bdev check to bio_devname()
2006-07-17 Li Guanglei <guanglei@cn.ibm.com>
-
- * syscalls.stp: make sys_acct, sys_add_key, sys_keyctl
- and sys_modify_ldt optional on ppc64 since they are
+
+ * syscalls.stp: make sys_acct, sys_add_key, sys_keyctl
+ and sys_modify_ldt optional on ppc64 since they are
weak symbol.
* ppc64/syscalls.stp: remove syscall.acct, syscall.add_key
- and syscall.umask since they are already defined in
+ and syscall.umask since they are already defined in
syscalls.stp
-
+
2006-07-04 Martin Hunt <hunt@redhat.com>
* syscalls.stp, syscalls2.stp: Use user_string_quoted().
2006-07-04 Li Guanglei <guanglei@cn.ibm.com>
-
- * syscalls.stp, syscalls2.stp, ppc64/syscalls.stp:
- fix syscall.lstat, syscall.lstat64, syscall.newlstat.
- * ppc64/syscalls.stp: fix syscall.compat_sys_statfs and
+
+ * syscalls.stp, syscalls2.stp, ppc64/syscalls.stp:
+ fix syscall.lstat, syscall.lstat64, syscall.newlstat.
+ * ppc64/syscalls.stp: fix syscall.compat_sys_statfs and
syscall.sys32_open
2006-07-04 Li Guanglei <guanglei@cn.ibm.com>
-
+
* memory.stp: add addr_to_node() from Jose R. Santos
(jrs@us.ibm.com)
* syscalls.stp: typo for syscall.lstat
@@ -1617,17 +1622,17 @@
on faults, just return <unknown>.
(user_string2): New function.
(user_string_warn): New function.
-
+
2006-06-26 Martin Hunt <hunt@redhat.com>
* aux_syscalls.stp (_stp_ctime): New function.
(_struct_utimbuf_u): New function.
2006-06-25 Li Guanglei <guanglei@cn.ibm.com>
-
- * syscalls.stp: Changes to AIO related syscalls(io_setup,
+
+ * syscalls.stp: Changes to AIO related syscalls(io_setup,
io_submit, io_getevents, io_cancel, io_destroy)
-
+
2006-06-23 Thang Nguyen <thang.p.nguyen@intel.com>
* tcp.stp: Refined variables and added more
@@ -1657,10 +1662,10 @@
2006-06-09 Martin Hunt <hunt@redhat.com>
- * syscalls2.stp: Fixed the uid and gid calls.
+ * syscalls2.stp: Fixed the uid and gid calls.
2006-06-09 Li Guanglei <guanglei@cn.ibm.com>
-
+
* syscalls.stp: made sys_ftruncate64 optional since it doesn't
exist on 2.6.16*/ppc64
@@ -1689,7 +1694,7 @@
* syscalls2.stp (sys_write): Use text_strn().
* syscalls.stp (sys_lseek): Fix.
(sys_llseek): Fix.
-
+
* string.stp (text_str): New.
(text_strn): New.
@@ -1702,22 +1707,22 @@
(add_key): Comment out. This syscall is added by a xen patch
and may not be present.
(tux): Ditto.
-
+
* syscalls.stp (accept): Fix arg name.
2006-05-25 Martin Hunt <hunt@redhat.com>
* syscalls.stp: Add sys_fcntl and sys_listen.
- * syscalls2.stp: Commented out sys_socketcall because it only calls
+ * syscalls2.stp: Commented out sys_socketcall because it only calls
other system calls which are already probed.
2006-05-25 Martin Hunt <hunt@redhat.com>
-
+
* syscall*.stp: Change "0x%p" to "%p".
2006-05-25 Li Guanglei <guanglei@cn.ibm.com>
-
+
* scheduler.stp: add prev_task and next_task variable.
2006-05-24 Josh Stone <joshua.i.stone@intel.com>
@@ -1735,7 +1740,7 @@
* tapset/ioscheduler.stp: change . to -> operator to get the
elevator name
-
+
2006-05-18 Li Guanglei <guanglei@cn.ibm.com>
* tapset/LKET/*: tracing tapsets of LKET
@@ -1747,7 +1752,7 @@
* tapset/tskschedule.stp: deleted, merge into scheduler.stp
* tapset/scheduler.stp: incorporate tskschedule.stp
-
+
2006-05-17 Josh Stone <joshua.i.stone@intel.com>
* process.stp: Rename signal.send to signal_send and process.complete
@@ -1796,7 +1801,7 @@
2006-05-14 Martin Hunt <hunt@redhat.com>
* aux_syscalls.stp (_sys_open_flag_str): Rewrite in C so it
- is complete and works on different archs.
+ is complete and works on different archs.
2006-05-09 Josh Stone <joshua.i.stone@intel.com>
@@ -1843,18 +1848,18 @@
2006-03-06 Martin Hunt <hunt@redhat.com>
- * system.stp: New tapset.
+ * system.stp: New tapset.
2006-03-01 Martin Hunt <hunt@redhat.com>
- * aux_syscalls.stp (_struct_sockaddr_u): Parse sockaddr.
+ * aux_syscalls.stp (_struct_sockaddr_u): Parse sockaddr.
* syscalls.stp (bind): Call _struct_sockaddr_u().
* errno.stp (errno_str): Complete rewrite in C for speed and
accuracy.
(returnstr): New function for syscall tapet.
-
+
2006-02-22 Frank Ch. Eigler <fche@elastic.org>
* timestamp.stp (get_cycles): New function.
@@ -1885,9 +1890,9 @@
* aux_syscalls.stp (_struct_timeval_u): New function.
(_struct_timeval): New function.
(_struct_timespec_u): New function.
- (_struct_timespec): New function.
+ (_struct_timespec): New function.
(_struct_itimerval_u): New function:
- (_struct_itimerval): New function:
+ (_struct_itimerval): New function:
(_signal_name): New function.
(_module_flags_str): Fixed.
@@ -1895,13 +1900,13 @@
_struct_itimerval_u().
* syscalls.stp: Latest version. Many changes.
-
+
2006-02-08 Martin Hunt <hunt@redhat.com>
* aux_syscalls.stp(_msync_flag_str): Fix.
(_wait_opt_str): Fix.
* syscalls.stp: Latest.
-
+
2006-02-07 Martin Hunt <hunt@redhat.com>
* syscalls.stp: Latest.
diff --git a/tapset/utrace.stp b/tapset/utrace.stp
new file mode 100644
index 00000000..3831ca3c
--- /dev/null
+++ b/tapset/utrace.stp
@@ -0,0 +1,11 @@
+/* utrace-only subset of register accessors */
+
+
+%{
+#include "syscall.h"
+%}
+
+
+function _utrace_syscall_nr:long () %{
+ THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */
+%}
diff --git a/tapsets.cxx b/tapsets.cxx
index aa6a611d..4fa53a88 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -675,13 +675,8 @@ struct dwflpp
void get_module_dwarf(bool required = false, bool report = true)
{
- if (!module_dwarf && mod_info->dwarf_status != info_absent)
- {
- if (!sess.ignore_dwarf)
- module_dwarf = dwfl_module_getdwarf(module, &module_bias);
- mod_info->dwarf_status = (module_dwarf ? info_present : info_absent);
- }
-
+ module_dwarf = dwfl_module_getdwarf(module, &module_bias);
+ mod_info->dwarf_status = (module_dwarf ? info_present : info_absent);
if (!module_dwarf && report)
{
string msg = "cannot find ";
@@ -863,7 +858,7 @@ struct dwflpp
bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0 ||
fnmatch(prefixed_pattern.c_str(), cu_name.c_str(), 0) == 0);
if (t && sess.verbose>3)
- clog << "pattern '" << pattern << "' "
+ clog << "pattern '" << prefixed_pattern << "' "
<< "matches "
<< "CU '" << cu_name << "'" << "\n";
return t;
@@ -884,42 +879,8 @@ struct dwflpp
{
}
- // Called by dwfl_linux_kernel_report_offline(). We may not have
- // dwarf info for the kernel and/or modules, so remember this
- // module's pathname in case we need to extract elf info from it.
- // (Currently, we get all the elf info we need via elfutils -- if the
- // elf file exists -- so remembering the pathname isn't strictly needed.
- // But we still need to handle the case where there's no vmlinux.)
-
- static systemtap_session* this_session; // XXX: used only due to elfutils shortcoming
-
- static int pathname_caching_callback(const char *name, const char *path)
- {
- module_info *mi = new module_info(name);
- assert (this_session);
- this_session->module_cache->cache[name] = mi;
-
- if (this_session->ignore_vmlinux && path && name == TOK_KERNEL)
- {
- // report_kernel() in elfutils found vmlinux, but pretend it didn't.
- // Given a non-null path, returning 1 means keep reporting modules.
- mi->dwarf_status = info_absent;
- return 1;
- }
- else if (path)
- {
- mi->elf_path = path;
- return 1;
- }
-
- // No vmlinux. Here returning 0 to report_kernel() means go ahead
- // and keep reporting modules.
- assert(name == TOK_KERNEL);
- mi->dwarf_status = info_absent;
- return 0;
- }
- void setup(bool kernel, bool debuginfo_needed = true)
+ void setup_kernel(bool debuginfo_needed = true)
{
if (! sess.module_cache)
sess.module_cache = new module_cache ();
@@ -933,14 +894,6 @@ struct dwflpp
static const char *debug_path = (debuginfo_env_arr ?
debuginfo_env_arr : sess.kernel_release.c_str());
- static const Dwfl_Callbacks proc_callbacks =
- {
- dwfl_linux_proc_find_elf,
- dwfl_standard_find_debuginfo,
- NULL,
- & debuginfo_path
- };
-
static const Dwfl_Callbacks kernel_callbacks =
{
dwfl_linux_kernel_find_elf,
@@ -949,135 +902,110 @@ struct dwflpp
& debuginfo_path
};
- if (kernel)
- {
- dwfl = dwfl_begin (&kernel_callbacks);
- if (!dwfl)
- throw semantic_error ("cannot open dwfl");
- dwfl_report_begin (dwfl);
-
- int (*callback)(const char *name, const char *path);
- if (sess.consult_symtab && !sess.module_cache->paths_collected)
- {
- callback = pathname_caching_callback;
- sess.module_cache->paths_collected = true;
- }
- else
- callback = NULL;
-
- // XXX: we should not need to set this static variable just
- // for the callback. The following elfutils routine should
- // take some void* parameter to pass context to the callback.
- this_session = & sess;
- int rc = dwfl_linux_kernel_report_offline (dwfl,
- debug_path,
- /* selection predicate */
- callback);
- this_session = 0;
-
- if (debuginfo_needed)
- dwfl_assert (string("missing kernel ") +
- sess.kernel_release +
- string(" ") +
- sess.architecture +
- string(" debuginfo"),
- rc);
-
- // XXX: it would be nice if we could do a single
- // ..._report_offline call for an entire systemtap script, so
- // that a selection predicate would filter out modules outside
- // the union of all the requested wildcards. But we build
- // derived_probes one-by-one and we don't have lookahead.
-
- // XXX: a special case: if we have only kernel.* probe points,
- // we shouldn't waste time looking for module debug-info (and
- // vice versa).
-
- // NB: the result of an _offline call is the assignment of
- // virtualized addresses to relocatable objects such as
- // modules. These have to be converted to real addresses at
- // run time. See the dwarf_derived_probe ctor and its caller.
- }
- else
- {
- dwfl = dwfl_begin (&proc_callbacks);
- dwfl_report_begin (dwfl);
- if (!dwfl)
- throw semantic_error ("cannot open dwfl");
-
- throw semantic_error ("user-space probes not yet implemented");
- // XXX: Find pids or processes, do userspace stuff.
- }
+ 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,
+ debug_path,
+ NULL);
+
+ if (debuginfo_needed)
+ dwfl_assert (string("missing kernel ") +
+ sess.kernel_release +
+ string(" ") +
+ sess.architecture +
+ string(" debuginfo"),
+ rc);
+
+ // XXX: it would be nice if we could do a single
+ // ..._report_offline call for an entire systemtap script, so
+ // that a selection predicate would filter out modules outside
+ // the union of all the requested wildcards. But we build
+ // derived_probes one-by-one and we don't have lookahead.
+ // PR 3498.
+
+ // XXX: a special case: if we have only kernel.* probe points,
+ // we shouldn't waste time looking for module debug-info (and
+ // vice versa).
+
+ // NB: the result of an _offline call is the assignment of
+ // virtualized addresses to relocatable objects such as
+ // modules. These have to be converted to real addresses at
+ // run time. See the dwarf_derived_probe ctor and its caller.
dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
}
+ void setup_user(string module_name, bool debuginfo_needed = true)
+ {
+ // XXX: this is where the session -R parameter could come in
+ static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build";
+ static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
+ static char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr);
+ static const Dwfl_Callbacks user_callbacks =
+ {
+ NULL, /* dwfl_linux_kernel_find_elf, */
+ dwfl_standard_find_debuginfo,
+ dwfl_offline_section_address,
+ & debuginfo_path
+ };
- // -----------------------------------------------------------------
+ dwfl = dwfl_begin (&user_callbacks);
+ if (!dwfl)
+ throw semantic_error ("cannot open dwfl");
+ dwfl_report_begin (dwfl);
- static int module_caching_callback(Dwfl_Module * mod,
- void **,
- const char *name,
- Dwarf_Addr addr,
- void *param)
- {
- systemtap_session *sess = static_cast<systemtap_session*>(param);
- module_cache_t *cache = sess->module_cache;
- module_info *mi = NULL;
+ // XXX: should support buildid-based naming
- assert (cache);
+ Dwfl_Module *mod = dwfl_report_offline (dwfl,
+ module_name.c_str(),
+ module_name.c_str(),
+ -1);
+ // XXX: save mod!
- if (sess->ignore_vmlinux && name == TOK_KERNEL)
- // This wouldn't be called for vmlinux if vmlinux weren't there.
- return DWARF_CB_OK;
+ if (debuginfo_needed)
+ dwfl_assert (string("missing process ") +
+ module_name +
+ string(" ") +
+ sess.architecture +
+ string(" debuginfo"),
+ mod);
- if (cache->paths_collected)
- mi = cache->cache[name];
- if (!mi)
- {
- mi = new module_info(name);
- cache->cache[name] = mi;
- }
- mi->mod = mod;
- mi->addr = addr;
- return DWARF_CB_OK;
- }
+ // NB: the result of an _offline call is the assignment of
+ // virtualized addresses to relocatable objects such as
+ // modules. These have to be converted to real addresses at
+ // run time. See the dwarf_derived_probe ctor and its caller.
- void cache_modules_dwarf()
- {
- if (!sess.module_cache->dwarf_collected)
- {
- ptrdiff_t off = 0;
- do
- {
- if (pending_interrupts) return;
- off = dwfl_getmodules (dwfl, module_caching_callback,
- & sess, off);
- }
- while (off > 0);
- dwfl_assert("dwfl_getmodules", off == 0);
- sess.module_cache->dwarf_collected = true;
- }
+ dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
}
- void iterate_over_modules(int (* callback)(Dwfl_Module *, module_info *,
+
+
+ // -----------------------------------------------------------------
+
+ void iterate_over_modules(int (* callback)(Dwfl_Module *, void **,
const char *, Dwarf_Addr,
void *),
- void * data)
+ dwarf_query *data)
{
- cache_modules_dwarf();
-
- map<string, module_info*>::iterator i;
- for (i = sess.module_cache->cache.begin(); i != sess.module_cache->cache.end(); i++)
+ ptrdiff_t off = 0;
+ do
{
if (pending_interrupts) return;
- module_info *mi = i->second;
- int rc = callback (mi->mod, mi, mi->name, mi->addr, data);
- if (rc != DWARF_CB_OK) break;
+ off = dwfl_getmodules (dwfl, callback, data, off);
}
+ while (off > 0);
+ dwfl_assert("dwfl_getmodules", off == 0);
+
+ // PR6864 XXX: For dwarfless case (if .../vmlinux is missing), then the
+ // "kernel" module is not reported in the loop above. However, we
+ // may be able to make do with symbol table data.
}
+
// Defined after dwarf_query
void query_modules(dwarf_query *q);
@@ -2322,10 +2250,6 @@ struct dwflpp
};
-systemtap_session* dwflpp::this_session = 0; // XXX: used only due to elfutils shortcoming
-
-
-
enum
function_spec_type
@@ -2363,9 +2287,7 @@ struct dwarf_derived_probe: public derived_probe
long maxactive_val;
void printsig (std::ostream &o) const;
-
void join_group (systemtap_session& s);
-
void emit_probe_local_init(translator_output * o);
// Pattern registration helpers.
@@ -2379,6 +2301,40 @@ struct dwarf_derived_probe: public derived_probe
};
+struct uprobe_derived_probe: public derived_probe
+{
+ bool return_p;
+ string module; // * => unrestricted
+ int pid; // 0 => unrestricted
+ string section; // empty => absolute address
+ Dwarf_Addr address;
+ // bool has_maxactive;
+ // long maxactive_val;
+
+ uprobe_derived_probe (const string& function,
+ const string& filename,
+ int line,
+ const string& module,
+ int pid,
+ const string& section,
+ Dwarf_Addr dwfl_addr,
+ Dwarf_Addr addr,
+ dwarf_query & q,
+ Dwarf_Die* scope_die);
+
+ // alternate constructor for process(PID).statement(ADDR).absolute
+ uprobe_derived_probe (probe *base,
+ probe_point *location,
+ int pid,
+ Dwarf_Addr addr,
+ bool return_p);
+
+ void printsig (std::ostream &o) const;
+ void join_group (systemtap_session& s);
+};
+
+
+
struct dwarf_derived_probe_group: public derived_probe_group
{
private:
@@ -2422,6 +2378,8 @@ struct base_query
// Extracted parameters.
bool has_kernel;
+ bool has_module;
+ bool has_process;
string module_val; // has_kernel => module_val = "kernel"
virtual void handle_query_module() = 0;
@@ -2437,15 +2395,21 @@ base_query::base_query(systemtap_session & sess,
: sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw),
results(results)
{
- has_kernel = has_null_param(params, TOK_KERNEL);
+ has_kernel = has_null_param (params, TOK_KERNEL);
if (has_kernel)
module_val = "kernel";
+
+ has_module = get_string_param (params, TOK_MODULE, module_val);
+ if (has_module)
+ has_process = false;
else
{
- bool has_module = get_string_param(params, TOK_MODULE, module_val);
- assert (has_module); // no other options are possible by construction
- (void) has_module;
+ has_process = get_string_param(params, TOK_PROCESS, module_val);
+ if (has_process)
+ module_val = find_executable (module_val);
}
+
+ assert (has_kernel || has_process || has_module);
}
bool
@@ -2726,23 +2690,40 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg),
struct dwarf_builder: public derived_probe_builder
{
dwflpp *kern_dw;
+ map <string,dwflpp*> user_dw;
dwarf_builder(): kern_dw(0) {}
- void build_no_more (systemtap_session &s)
+
+ /* NB: not virtual, so can be called from dtor too: */
+ void dwarf_build_no_more (bool verbose)
{
if (kern_dw)
{
- if (s.verbose > 3)
- clog << "dwarf_builder releasing dwflpp" << endl;
+ if (verbose)
+ clog << "dwarf_builder releasing kernel dwflpp" << endl;
delete kern_dw;
kern_dw = 0;
}
+
+ for (map<string,dwflpp*>::iterator udi = user_dw.begin();
+ udi != user_dw.end();
+ udi ++)
+ {
+ if (verbose)
+ clog << "dwarf_builder releasing user dwflpp " << udi->first << endl;
+ delete udi->second;
+ }
+ user_dw.erase (user_dw.begin(), user_dw.end());
+ }
+
+ void build_no_more (systemtap_session &s)
+ {
+ dwarf_build_no_more (s.verbose > 3);
}
~dwarf_builder()
{
- // XXX: in practice, NOTREACHED
- delete kern_dw;
+ dwarf_build_no_more (false);
}
virtual void build(systemtap_session & sess,
@@ -2924,6 +2905,10 @@ dwarf_query::handle_query_module()
void
dwarf_query::build_blacklist()
{
+ // No blacklist for userspace.
+ if (has_process)
+ return;
+
// We build up the regexps in these strings
// Add ^ anchors at the front; $ will be added just before regcomp.
@@ -3132,9 +3117,11 @@ dwarf_query::parse_function_spec(string & spec)
}
+#if 0
// Forward declaration.
-static int query_kernel_module (Dwfl_Module *, module_info *, const char *,
+static int query_kernel_module (Dwfl_Module *, void **, const char *,
Dwarf_Addr, void *);
+#endif
// XXX: pull this into dwflpp
@@ -3160,6 +3147,9 @@ dwarf_query::blacklisted_p(const string& funcname,
const string& section,
Dwarf_Addr addr)
{
+ if (has_process)
+ return false; // no blacklist for userspace
+
if (section.substr(0, 6) == string(".init.") ||
section.substr(0, 6) == string(".exit.") ||
section.substr(0, 9) == string(".devinit.") ||
@@ -3249,7 +3239,6 @@ dwarf_query::add_probe_point(const string& funcname,
Dwarf_Die* scope_die,
Dwarf_Addr addr)
{
- dwarf_derived_probe *probe = NULL;
string reloc_section; // base section for relocation purposes
Dwarf_Addr reloc_addr = addr; // relocated
string blacklist_section; // linking section for blacklist purposes
@@ -3265,7 +3254,7 @@ dwarf_query::add_probe_point(const string& funcname,
}
else if (dwfl_module_relocations (dw.module) > 0)
{
- // This is arelocatable module; libdwfl already knows its
+ // This is a relocatable module; libdwfl already knows its
// sections, so we can relativize addr.
int idx = dwfl_module_relocate_address (dw.module, &reloc_addr);
const char* r_s = dwfl_module_relocation_info (dw.module, idx, NULL);
@@ -3274,12 +3263,16 @@ dwarf_query::add_probe_point(const string& funcname,
blacklist_section = reloc_section;
if(reloc_section == "" && dwfl_module_relocations (dw.module) == 1)
- blacklist_section = this->get_blacklist_section(addr);
+ {
+ blacklist_section = this->get_blacklist_section(addr);
+ reloc_section = ".dynamic";
+ reloc_addr = addr;
+ }
}
else
{
blacklist_section = this->get_blacklist_section(addr);
- reloc_section = "";
+ reloc_section = ".absolute";
}
if (sess.verbose > 1)
@@ -3287,8 +3280,10 @@ dwarf_query::add_probe_point(const string& funcname,
clog << "probe " << funcname << "@" << filename << ":" << line;
if (string(module) == TOK_KERNEL)
clog << " kernel";
- else
+ else if (has_module)
clog << " module=" << module;
+ else if (has_process)
+ clog << " process=" << module;
if (reloc_section != "") clog << " reloc=" << reloc_section;
if (blacklist_section != "") clog << " section=" << blacklist_section;
clog << " pc=0x" << hex << addr << dec;
@@ -3308,9 +3303,20 @@ dwarf_query::add_probe_point(const string& funcname,
if (! bad)
{
sess.unwindsym_modules.insert (module);
- probe = new dwarf_derived_probe(funcname, filename, line,
- module, reloc_section, addr, reloc_addr, *this, scope_die);
- results.push_back(probe);
+
+ if (has_process)
+ {
+ results.push_back (new uprobe_derived_probe(funcname, filename, line,
+ module, 0, reloc_section, addr, reloc_addr,
+ *this, scope_die));
+ }
+ else
+ {
+ assert (has_kernel || has_module);
+ results.push_back (new dwarf_derived_probe(funcname, filename, line,
+ module, reloc_section, addr, reloc_addr,
+ *this, scope_die));
+ }
}
}
@@ -3447,7 +3453,8 @@ query_func_info (Dwarf_Addr entrypc,
else
{
if (q->sess.prologue_searching
- && !q->has_statement_str && !q->has_statement_num) // PR 2608
+ && !q->has_statement_str && !q->has_statement_num
+ && !q->sess.ignore_vmlinux && !q->sess.ignore_dwarf) // PR 2608
{
if (fi.prologue_end == 0)
throw semantic_error("could not find prologue-end "
@@ -3762,9 +3769,10 @@ query_cu (Dwarf_Die * cudie, void * arg)
}
+#if 0
static int
query_kernel_module (Dwfl_Module *mod,
- module_info *,
+ void **,
const char *name,
Dwarf_Addr,
void *arg)
@@ -3778,6 +3786,8 @@ query_kernel_module (Dwfl_Module *mod,
}
return DWARF_CB_OK;
}
+#endif
+
static void
validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
@@ -3844,17 +3854,69 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
<< "\n";
}
+
+
+static Dwarf_Addr
+lookup_symbol_address (Dwfl_Module *m, const char* wanted)
+{
+ 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 != NULL && strcmp(name, wanted) == 0)
+ return sym.st_value;
+ }
+
+ return 0;
+}
+
+
+
static int
query_module (Dwfl_Module *mod,
- module_info *mi,
+ void **,
const char *name,
- Dwarf_Addr,
+ Dwarf_Addr addr,
void *arg)
{
- base_query * q = static_cast<base_query *>(arg);
+ base_query *q = static_cast<base_query *>(arg);
try
{
+ module_info* mi = q->sess.module_cache->cache[name];
+ if (mi == 0)
+ {
+ mi = q->sess.module_cache->cache[name] = new module_info(name);
+
+ mi->mod = mod;
+ mi->addr = addr;
+
+ const char* debug_filename = "";
+ const char* main_filename = "";
+ (void) dwfl_module_info (mod, NULL, NULL,
+ NULL, NULL, NULL,
+ & main_filename,
+ & debug_filename);
+
+ if (q->sess.ignore_vmlinux && name == TOK_KERNEL)
+ {
+ // report_kernel() in elfutils found vmlinux, but pretend it didn't.
+ // Given a non-null path, returning 1 means keep reporting modules.
+ mi->dwarf_status = info_absent;
+ }
+ else if (debug_filename || main_filename)
+ {
+ mi->elf_path = debug_filename ?: main_filename;
+ }
+ else if (name == TOK_KERNEL)
+ {
+ mi->dwarf_status = info_absent;
+ }
+ }
+ // OK, enough of that module_info caching business.
+
q->dw.focus_on_module(mod, mi);
// If we have enough information in the pattern to skip a module and
@@ -3871,14 +3933,28 @@ query_module (Dwfl_Module *mod,
if (mod)
validate_module_elf(mod, name, q);
else
+ assert(q->has_kernel); // and no vmlinux to examine
+
+ if (q->sess.verbose>2)
+ cerr << "focused on module '" << q->dw.module_name << "'\n";
+
+
+ // Collect a few kernel addresses. XXX: these belong better
+ // to the sess.module_info["kernel"] struct.
+ if (q->dw.module_name == TOK_KERNEL)
{
- assert(q->has_kernel); // and no vmlinux to examine
- if (q->sess.verbose>2)
- cerr << "focused on module '" << q->dw.module_name << "'\n";
+ if (! q->sess.sym_kprobes_text_start)
+ q->sess.sym_kprobes_text_start = lookup_symbol_address (mod, "__kprobes_text_start");
+ if (! q->sess.sym_kprobes_text_end)
+ q->sess.sym_kprobes_text_end = lookup_symbol_address (mod, "__kprobes_text_end");
+ if (! q->sess.sym_stext)
+ q->sess.sym_stext = lookup_symbol_address (mod, "_stext");
}
+ // Finally, search the module for matches of the probe point.
q->handle_query_module();
+
// If we know that there will be no more matches, abort early.
if (q->dw.module_name_final_match(q->module_val))
return DWARF_CB_ABORT;
@@ -3895,20 +3971,7 @@ query_module (Dwfl_Module *mod,
void
dwflpp::query_modules(dwarf_query *q)
{
- string name = q->module_val;
- if (name_has_wildcard(name))
- iterate_over_modules(&query_module, q);
- else
- {
- cache_modules_dwarf();
-
- map<string, module_info*>::iterator i = sess.module_cache->cache.find(name);
- if (i != sess.module_cache->cache.end())
- {
- module_info *mi = i->second;
- query_module(mi->mod, mi, name.c_str(), mi->addr, q);
- }
- }
+ iterate_over_modules(&query_module, q);
}
struct var_expanding_copy_visitor: public deep_copy_visitor
@@ -4488,7 +4551,7 @@ dwarf_derived_probe::printsig (ostream& o) const
// function instances. This is distinct from the verbose/clog
// output, since this part goes into the cache hash calculations.
sole_location()->print (o);
- o << " /* pc=0x" << hex << addr << dec << " */";
+ o << " /* pc=" << section << "+0x" << hex << addr << dec << " */";
printsig_nested (o);
}
@@ -4506,7 +4569,7 @@ dwarf_derived_probe::join_group (systemtap_session& s)
dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
const string& filename,
int line,
- // module & section speficy a relocation
+ // module & section specify a relocation
// base for <addr>, unless section==""
// (equivalently module=="kernel")
const string& module,
@@ -4572,10 +4635,14 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
// number any particular match of the wildcards.
vector<probe_point::component*> comps;
- comps.push_back
- (module == TOK_KERNEL
- ? new probe_point::component(TOK_KERNEL)
- : new probe_point::component(TOK_MODULE, new literal_string(module)));
+ if (q.has_kernel)
+ comps.push_back (new probe_point::component(TOK_KERNEL));
+ else if(q.has_module)
+ comps.push_back (new probe_point::component(TOK_MODULE, new literal_string(module)));
+ else if(q.has_process)
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(module)));
+ else
+ assert (0);
string fn_or_stmt;
if (q.has_function_str || q.has_function_num)
@@ -4588,9 +4655,9 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
string retro_name = funcname;
if (filename != "")
{
- retro_name += ("@" + string (filename));
+ retro_name += ("@" + string (filename));
if (line > 0)
- retro_name += (":" + lex_cast<string> (line));
+ retro_name += (":" + lex_cast<string> (line));
}
comps.push_back
(new probe_point::component
@@ -4670,7 +4737,7 @@ dwarf_derived_probe::register_patterns(match_node * root)
register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw);
root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw);
- // register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw);
+ register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw);
}
void
@@ -4856,7 +4923,7 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];";
s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address);";
s.op->newline() << "if (relocated_addr == 0) continue;"; // quietly; assume module is absent
- s.op->newline() << "probe_point = sdp->pp;";
+ s.op->newline() << "probe_point = sdp->pp;"; // for error messages
s.op->newline() << "if (sdp->return_p) {";
s.op->newline(1) << "kp->u.krp.kp.addr = (void *) relocated_addr;";
s.op->newline() << "if (sdp->maxactive_p) {";
@@ -4973,26 +5040,6 @@ dwarf_derived_probe_group::emit_module_exit (systemtap_session& s)
}
-
-static Dwarf_Addr
-lookup_symbol_address (Dwfl_Module *m, const char* wanted)
-{
- 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 != NULL && strcmp(name, wanted) == 0)
- return sym.st_value;
- }
-
- return 0;
-}
-
-
-
-
void
dwarf_builder::build(systemtap_session & sess,
probe * base,
@@ -5004,39 +5051,49 @@ dwarf_builder::build(systemtap_session & sess,
// XXX: but they should be per-session, as this builder object
// may be reused if we try to cross-instrument multiple targets.
- if (!kern_dw)
+ dwflpp* dw = 0;
+
+ if (! sess.module_cache)
+ sess.module_cache = new module_cache ();
+
+ string module_name;
+ if (has_null_param (parameters, TOK_KERNEL)
+ || get_param (parameters, TOK_MODULE, module_name))
{
- kern_dw = new dwflpp(sess);
- assert(kern_dw);
- kern_dw->setup(true);
+ // kernel or kernel module target
+ if (! kern_dw)
+ {
+ kern_dw = new dwflpp(sess);
+ // XXX: PR 3498, PR 6864
+ kern_dw->setup_kernel(true);
+ }
+ dw = kern_dw;
}
-
- Dwfl_Module* km = 0;
- kern_dw->iterate_over_modules(&query_kernel_module, &km);
- if (km)
+ else if (get_param (parameters, TOK_PROCESS, module_name))
{
- if (! sess.sym_kprobes_text_start)
- sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start");
- if (! sess.sym_kprobes_text_end)
- sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end");
- if (! sess.sym_stext)
- sess.sym_stext = lookup_symbol_address (km, "_stext");
+ module_name = find_executable (module_name); // canonicalize it
- if (sess.verbose > 2)
+ // user-space target; we use one dwflpp instance per module name
+ // (= program or shared library)
+ if (user_dw.find(module_name) == user_dw.end())
{
- clog << "control symbols:"
- // abbreviate the names - they're for our debugging only anyway
- << " kts: 0x" << hex << sess.sym_kprobes_text_start
- << " kte: 0x" << sess.sym_kprobes_text_end
- << " stext: 0x" << sess.sym_stext
- << dec << endl;
+ dw = new dwflpp(sess);
+ // XXX: PR 3498
+ dw->setup_user(module_name);
+ user_dw[module_name] = dw;
}
+ else
+ dw = user_dw[module_name];
}
- dwflpp* dw = kern_dw;
+
dwarf_query q(sess, base, location, *dw, parameters, finished_results);
- if (q.has_absolute)
+
+ // XXX: kernel.statement.absolute is a special case that requires no
+ // dwfl processing. This code should be in a separate builder.
+
+ if (q.has_kernel && q.has_absolute)
{
// assert guru mode for absolute probes
if (! q.base_probe->privileged)
@@ -5056,7 +5113,6 @@ dwarf_builder::build(systemtap_session & sess,
return;
}
- // dw->iterate_over_modules(&query_module, &q);
dw->query_modules(&q);
}
@@ -5385,7 +5441,6 @@ module_info::get_symtab(dwarf_query *q)
sess.sym_kprobes_text_end =
sym_table->lookup_symbol_address("__kprobes_text_end");
sess.sym_stext = sym_table->lookup_symbol_address("_stext");
- bias = sym_table->lookup_symbol_address("_text");
}
}
}
@@ -5445,21 +5500,7 @@ void
task_finder_derived_probe_group::create_session_group (systemtap_session& s)
{
if (! s.task_finder_derived_probes)
- {
- s.task_finder_derived_probes = new task_finder_derived_probe_group();
-
- // Make sure we've got the stuff we need early in the output code.
- embeddedcode *ec = new embeddedcode;
- ec->tok = NULL;
- ec->code = string("#if ! defined(CONFIG_UTRACE)\n")
- + string("#error \"Need CONFIG_UTRACE!\"\n")
- + string("#endif\n")
- + string("#include <linux/utrace.h>\n")
- + string("#include <linux/mount.h>\n")
- + string("#include \"task_finder.c\"\n");
-
- s.embeds.push_back(ec);
- }
+ s.task_finder_derived_probes = new task_finder_derived_probe_group();
}
@@ -5471,8 +5512,7 @@ task_finder_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline() << "rc = stap_start_task_finder();";
s.op->newline() << "if (rc) {";
- s.op->indent(1);
- s.op->newline() << "stap_stop_task_finder();";
+ s.op->newline(1) << "stap_stop_task_finder();";
s.op->newline(-1) << "}";
}
@@ -5556,52 +5596,23 @@ struct itrace_builder: public derived_probe_builder
vector<derived_probe *> & finished_results)
{
string path;
- int64_t pid;
+ int64_t pid = 0;
int single_step;
bool has_path = get_param (parameters, TOK_PROCESS, path);
bool has_pid = get_param (parameters, TOK_PROCESS, pid);
+ // XXX: PR 6445 needs !has_path && !has_pid support
assert (has_path || has_pid);
single_step = 1;
// If we have a path, we need to validate it.
if (has_path)
- {
- string::size_type start_pos, end_pos;
- string component;
-
- // Make sure it starts with '/'.
- if (path[0] != '/')
- throw semantic_error ("process path must start with a '/'",
- location->tok);
-
- start_pos = 1; // get past the initial '/'
- while ((end_pos = path.find('/', start_pos)) != string::npos)
- {
- component = path.substr(start_pos, end_pos - start_pos);
- // Make sure it isn't empty.
- if (component.size() == 0)
- throw semantic_error ("process path component cannot be empty",
- location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
-
- start_pos = end_pos + 1;
- }
- component = path.substr(start_pos);
- // Make sure it doesn't end with '/'.
- if (component.size() == 0)
- throw semantic_error ("process path cannot end with a '/'", location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
- }
+ path = find_executable (path);
finished_results.push_back(new itrace_derived_probe(sess, base, location,
has_path, path, pid,
- single_step
+ single_step
));
}
};
@@ -5830,26 +5841,64 @@ struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor
string probe_name;
enum utrace_derived_probe_flags flags;
bool target_symbol_seen;
- static bool syscall_function_added;
void visit_target_symbol (target_symbol* e);
};
-bool utrace_var_expanding_copy_visitor::syscall_function_added = false;
-
utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
probe* p, probe_point* l,
bool hp, string &pn, int64_t pd,
enum utrace_derived_probe_flags f):
- derived_probe(p, l), has_path(hp), path(pn), pid(pd), flags(f),
+ derived_probe (p, new probe_point (*l) /* .components soon rewritten */ ),
+ has_path(hp), path(pn), pid(pd), flags(f),
target_symbol_seen(false)
{
// Make a local-variable-expanded copy of the probe body
utrace_var_expanding_copy_visitor v (s, name, flags);
require <statement*> (&v, &(this->body), base->body);
target_symbol_seen = v.target_symbol_seen;
+
+ // Reset the sole element of the "locations" vector as a
+ // "reverse-engineered" form of the incoming (q.base_loc) probe
+ // point. This allows a user to see what program etc.
+ // number any particular match of the wildcards.
+
+ vector<probe_point::component*> comps;
+ if (hp)
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
+ else
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
+ switch (flags)
+ {
+ case UDPF_THREAD_BEGIN:
+ comps.push_back (new probe_point::component(TOK_THREAD));
+ comps.push_back (new probe_point::component(TOK_BEGIN));
+ break;
+ case UDPF_THREAD_END:
+ comps.push_back (new probe_point::component(TOK_THREAD));
+ comps.push_back (new probe_point::component(TOK_END));
+ break;
+ case UDPF_SYSCALL:
+ comps.push_back (new probe_point::component(TOK_SYSCALL));
+ break;
+ case UDPF_SYSCALL_RETURN:
+ comps.push_back (new probe_point::component(TOK_SYSCALL));
+ comps.push_back (new probe_point::component(TOK_RETURN));
+ break;
+ case UDPF_BEGIN:
+ comps.push_back (new probe_point::component(TOK_BEGIN));
+ break;
+ case UDPF_END:
+ comps.push_back (new probe_point::component(TOK_END));
+ break;
+ default:
+ assert (0);
+ }
+
+ // Overwrite it.
+ this->sole_location()->components = comps;
}
@@ -5905,27 +5954,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
// Remember that we've seen a target variable.
target_symbol_seen = true;
- // Synthesize a function to grab the syscall .
- if (! syscall_function_added)
- {
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
- ec->code = string("THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */");
-
- fdecl->name = string("_syscall_nr_get");
- fdecl->body = ec;
- fdecl->type = pe_long;
- sess.functions.push_back(fdecl);
- syscall_function_added = true;
- }
-
// We're going to substitute a synthesized '_syscall_nr_get'
// function call for the '$syscall' reference.
functioncall* n = new functioncall;
n->tok = e->tok;
- n->function = "_syscall_nr_get";
+ n->function = "_utrace_syscall_nr";
n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
provide <functioncall*> (this, n);
@@ -5976,51 +6009,19 @@ struct utrace_builder: public derived_probe_builder
has_pid = true;
pid = 0;
}
- // Validate pid.
+ else if (has_path)
+ {
+ path = find_executable (path);
+ sess.unwindsym_modules.insert (path);
+ }
else if (has_pid)
{
- // We can't probe 'init' (pid 1).
+ // We can't probe 'init' (pid 1). XXX: where does this limitation come from?
if (pid < 2)
throw semantic_error ("process pid must be greater than 1",
location->tok);
- }
- // If we have a regular path, we need to validate it.
- else if (has_path)
- {
- string::size_type start_pos, end_pos;
- string component;
-
- // XXX: these checks should be done in terms of filesystem
- // operations.
-
- // Make sure it starts with '/'.
- if (path[0] != '/')
- throw semantic_error ("process path must start with a '/'",
- location->tok);
- start_pos = 1; // get past the initial '/'
- while ((end_pos = path.find('/', start_pos)) != string::npos)
- {
- component = path.substr(start_pos, end_pos - start_pos);
- // Make sure it isn't empty.
- if (component.size() == 0)
- throw semantic_error ("process path component cannot be empty",
- location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
-
- start_pos = end_pos + 1;
- }
- component = path.substr(start_pos);
- // Make sure it doesn't end with '/'.
- if (component.size() == 0)
- throw semantic_error ("process path cannot end with a '/'", location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
-
- sess.unwindsym_modules.insert (path);
+ // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere?
}
finished_results.push_back(new utrace_derived_probe(sess, base, location,
@@ -6163,6 +6164,8 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "/* ---- utrace probes ---- */";
+ s.op->newline() << "#include \"task_finder.c\"";
+
s.op->newline() << "enum utrace_derived_probe_flags {";
s.op->indent(1);
s.op->newline() << "UDPF_NONE,";
@@ -6350,7 +6353,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "break;";
s.op->indent(-1);
}
-
+
if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "case UDPF_SYSCALL:";
@@ -6474,15 +6477,6 @@ utrace_derived_probe_group::emit_module_exit (systemtap_session& s)
// user-space probes
// ------------------------------------------------------------------------
-struct uprobe_derived_probe: public derived_probe
-{
- uint64_t process, address;
- bool return_p;
- uprobe_derived_probe (systemtap_session &s, probe* p, probe_point* l,
- uint64_t, uint64_t, bool);
- void join_group (systemtap_session& s);
-};
-
struct uprobe_derived_probe_group: public generic_dpg<uprobe_derived_probe>
{
@@ -6493,12 +6487,128 @@ public:
};
-uprobe_derived_probe::uprobe_derived_probe (systemtap_session &s,
- probe* p, probe_point* l,
- uint64_t pp, uint64_t aa, bool rr):
- derived_probe(p, l), process(pp), address(aa), return_p (rr)
+uprobe_derived_probe::uprobe_derived_probe (const string& function,
+ const string& filename,
+ int line,
+ const string& module,
+ int pid,
+ const string& section,
+ Dwarf_Addr dwfl_addr,
+ Dwarf_Addr addr,
+ dwarf_query & q,
+ Dwarf_Die* scope_die /* may be null */):
+ derived_probe (q.base_probe, new probe_point (*q.base_loc) /* .components soon rewritten */ ),
+ return_p (q.has_return), module (module), pid (pid), section (section), address (addr)
+{
+ // We may receive probes on two types of ELF objects: ET_EXEC or ET_DYN.
+ // ET_EXEC ones need no further relocation on the addr(==dwfl_addr), whereas
+ // ET_DYN ones do (addr += run-time mmap base address). We tell these apart
+ // by the incoming section value (".absolute" vs. ".dynamic").
+
+ this->tok = q.base_probe->tok;
+
+ // Make a target-variable-expanded copy of the probe body
+ if (!null_die(scope_die))
+ {
+ dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr); // XXX: user-space deref's!
+ require <statement*> (&v, &(this->body), this->body);
+
+ // If during target-variable-expanding the probe, we added a new block
+ // of code, add it to the start of the probe.
+ if (v.add_block)
+ this->body = new block(v.add_block, this->body);
+
+ // If when target-variable-expanding the probe, we added a new
+ // probe, add it in a new file to the list of files to be processed.
+ if (v.add_probe)
+ {
+ stapfile *f = new stapfile;
+ f->probes.push_back(v.add_probe);
+ q.sess.files.push_back(f);
+ }
+ }
+ // else - null scope_die - $target variables will produce an error during translate phase
+
+ // Reset the sole element of the "locations" vector as a
+ // "reverse-engineered" form of the incoming (q.base_loc) probe
+ // point. This allows a user to see what function / file / line
+ // number any particular match of the wildcards.
+
+ vector<probe_point::component*> comps;
+ if(q.has_process)
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(module)));
+ else
+ assert (0);
+
+ string fn_or_stmt;
+ if (q.has_function_str || q.has_function_num)
+ fn_or_stmt = "function";
+ else
+ fn_or_stmt = "statement";
+
+ if (q.has_function_str || q.has_statement_str)
+ {
+ string retro_name = function;
+ if (filename != "")
+ {
+ retro_name += ("@" + string (filename));
+ if (line > 0)
+ retro_name += (":" + lex_cast<string> (line));
+ }
+ comps.push_back
+ (new probe_point::component
+ (fn_or_stmt, new literal_string (retro_name)));
+ }
+ else if (q.has_function_num || q.has_statement_num)
+ {
+ Dwarf_Addr retro_addr;
+ if (q.has_function_num)
+ retro_addr = q.function_num_val;
+ else
+ retro_addr = q.statement_num_val;
+ comps.push_back (new probe_point::component
+ (fn_or_stmt,
+ new literal_number(retro_addr))); // XXX: should be hex if possible
+
+ if (q.has_absolute)
+ comps.push_back (new probe_point::component (TOK_ABSOLUTE));
+ }
+
+ if (q.has_call)
+ comps.push_back (new probe_point::component(TOK_CALL));
+ if (q.has_inline)
+ comps.push_back (new probe_point::component(TOK_INLINE));
+ if (return_p)
+ comps.push_back (new probe_point::component(TOK_RETURN));
+ /*
+ if (has_maxactive)
+ comps.push_back (new probe_point::component
+ (TOK_MAXACTIVE, new literal_number(maxactive_val)));
+ */
+
+ // Overwrite it.
+ this->sole_location()->components = comps;
+}
+
+
+uprobe_derived_probe::uprobe_derived_probe (probe *base,
+ probe_point *location,
+ int pid,
+ Dwarf_Addr addr,
+ bool has_return):
+ derived_probe (base, location), // location is not rewritten here
+ return_p (has_return), pid (pid), address (addr)
{
- s.need_uprobes = true;
+}
+
+
+void
+uprobe_derived_probe::printsig (ostream& o) const
+{
+ // Same as dwarf_derived_probe.
+ sole_location()->print (o);
+ o << " /* pc=" << section << "+0x" << hex << address << dec << " */";
+ printsig_nested (o);
}
@@ -6508,6 +6618,7 @@ uprobe_derived_probe::join_group (systemtap_session& s)
if (! s.uprobe_derived_probes)
s.uprobe_derived_probes = new uprobe_derived_probe_group ();
s.uprobe_derived_probes->enroll (this);
+ task_finder_derived_probe_group::create_session_group (s);
}
@@ -6529,8 +6640,7 @@ struct uprobe_builder: public derived_probe_builder
bool rr = has_null_param (parameters, TOK_RETURN);
assert (b1 && b2); // by pattern_root construction
- finished_results.push_back(new uprobe_derived_probe(sess, base, location,
- process, address, rr));
+ finished_results.push_back(new uprobe_derived_probe(base, location, process, address, rr));
}
};
@@ -6541,29 +6651,52 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
if (probes.empty()) return;
s.op->newline() << "/* ---- user probes ---- */";
+ s.need_uprobes = true; // Ask buildrun.cxx to build extra module if needed
+
// If uprobes isn't in the kernel, pull it in from the runtime.
s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)";
s.op->newline() << "#include <linux/uprobes.h>";
s.op->newline() << "#else";
s.op->newline() << "#include \"uprobes/uprobes.h\"";
s.op->newline() << "#endif";
+ s.op->newline() << "#include \"task_finder.c\"";
+
+ s.op->newline() << "#ifndef MAXUPROBES";
+ s.op->newline() << "#define MAXUPROBES 16"; // maximum possible armed uprobes per process() probe point
+ s.op->newline() << "#endif";
+ s.op->newline() << "#define NUMUPROBES (MAXUPROBES*" << probes.size() << ")";
+ // In .bss, the shared pool of uprobe/uretprobe structs. These are
+ // too big to embed in the initialized .data stap_uprobe_spec array.
s.op->newline() << "struct stap_uprobe {";
s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };";
- s.op->newline() << "unsigned registered_p:1;";
- s.op->newline() << "unsigned return_p:1;";
- s.op->newline() << "unsigned long process;";
+ s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered
+ s.op->newline(-1) << "} stap_uprobes [NUMUPROBES];";
+ s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration
+
+ s.op->newline() << "struct stap_uprobe_spec {";
+ s.op->newline(1) << "struct stap_task_finder_target finder;";
s.op->newline() << "unsigned long address;";
+ s.op->newline() << "const char *pathname;";
s.op->newline() << "const char *pp;";
s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline(-1) << "} stap_uprobes [] = {";
+ s.op->newline() << "unsigned return_p:1;";
+ s.op->newline(-1) << "} stap_uprobe_specs [] = {";
s.op->indent(1);
for (unsigned i =0; i<probes.size(); i++)
{
uprobe_derived_probe* p = probes[i];
s.op->newline() << "{";
+ s.op->line() << " .finder = {";
+ if (p->pid != 0)
+ s.op->line() << " .pid=" << p->pid;
+ else if (p->section == ".absolute")
+ s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", ";
+ // else ".dynamic" gets pathname=0, pid=0, activating task_finder "global tracing"
+ s.op->line() << "},";
+ if (p->section != ".absolute")
+ s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", ";
s.op->line() << " .address=0x" << hex << p->address << dec << "UL,";
- s.op->line() << " .process=" << p->process << ",";
s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
s.op->line() << " .ph=&" << p->name << ",";
if (p->return_p) s.op->line() << " .return_p=1,";
@@ -6571,81 +6704,225 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
}
s.op->newline(-1) << "};";
- s.op->newline();
- s.op->newline() << "void enter_uprobe_probe (struct uprobe *inst, struct pt_regs *regs) {";
+ s.op->newline() << "static void enter_uprobe_probe (struct uprobe *inst, struct pt_regs *regs) {";
s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst, struct stap_uprobe, up);";
+ s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
- s.op->newline() << "c->probe_point = sup->pp;";
+ s.op->newline() << "if (sup->spec_index < 0 ||"
+ << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen
+ s.op->newline() << "c->probe_point = sups->pp;";
s.op->newline() << "c->regs = regs;";
- s.op->newline() << "(*sup->ph) (c);";
+ s.op->newline() << "(*sups->ph) (c);";
common_probe_entryfn_epilogue (s.op);
s.op->newline(-1) << "}";
- s.op->newline() << "void enter_uretprobe_probe (struct uretprobe_instance *inst, struct pt_regs *regs) {";
+ s.op->newline() << "static void enter_uretprobe_probe (struct uretprobe_instance *inst, struct pt_regs *regs) {";
s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst->rp, struct stap_uprobe, urp);";
+ s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
- s.op->newline() << "c->probe_point = sup->pp;";
+ s.op->newline() << "if (sup->spec_index < 0 ||"
+ << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen
+ s.op->newline() << "c->probe_point = sups->pp;";
// XXX: kretprobes saves "c->pi = inst;" too
s.op->newline() << "c->regs = regs;";
- s.op->newline() << "(*sup->ph) (c);";
+ s.op->newline() << "(*sups->ph) (c);";
common_probe_entryfn_epilogue (s.op);
s.op->newline(-1) << "}";
-}
-void
-uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
- s.op->newline() << "/* ---- user probes ---- */";
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ // NB: Because these utrace callbacks only occur before / after
+ // userspace instructions run, there is no concurrency control issue
+ // between active uprobe callbacks and these registration /
+ // unregistration pieces.
+
+ // We protect the stap_uprobe->spec_index (which also serves as a
+ // free/busy flag) value with the outer protective probes_lock
+ // mutex, to protect it against concurrent registration /
+ // unregistration. XXX: This should become less naive and let the
+ // mutex only protect stap_uprobe slot allocation and let the uprobe
+ // calls occur outside the critical section.
+
+ s.op->newline();
+ s.op->newline() << "static int stap_uprobe_change (struct task_struct *tsk, int register_p, unsigned long relocation, struct stap_uprobe_spec *sups) {";
+ s.op->newline(1) << "int spec_index = (sups - stap_uprobe_specs);";
+ s.op->newline() << "int handled_p = 0;";
+ s.op->newline() << "int rc = 0;";
+ s.op->newline() << "int i;";
+ s.op->newline() << "mutex_lock (& stap_uprobes_lock);";
+
+ s.op->newline() << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uprobe idx %d change pid %d register_p %d reloc %p pp %s\\n\", spec_index, tsk->tgid, register_p, (void*) relocation, sups->pp);";
+ s.op->newline() << "#endif";
+
+ s.op->newline() << "for (i=0; i<NUMUPROBES; i++) {"; // XXX: slow linear search
s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];";
- s.op->newline() << "probe_point = sup->pp;";
- s.op->newline() << "if (sup->return_p) {";
- s.op->newline(1) << "sup->urp.u.pid = sup->process;";
- s.op->newline() << "sup->urp.u.vaddr = sup->address;";
+
+ // register new uprobe
+ s.op->newline() << "if (register_p && sup->spec_index < 0) {";
+ s.op->newline(1) << "sup->spec_index = spec_index;";
+ s.op->newline() << "if (sups->return_p) {";
+ s.op->newline(1) << "sup->urp.u.pid = tsk->tgid;";
+ s.op->newline() << "sup->urp.u.vaddr = relocation + sups->address;";
s.op->newline() << "sup->urp.handler = &enter_uretprobe_probe;";
+ s.op->newline() << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uretprobe register pid %d addr %p\\n\", sup->urp.u.pid, (void*) sup->urp.u.vaddr);";
+ s.op->newline() << "#endif";
s.op->newline() << "rc = register_uretprobe (& sup->urp);";
s.op->newline(-1) << "} else {";
- s.op->newline(1) << "sup->up.pid = sup->process;";
- s.op->newline() << "sup->up.vaddr = sup->address;";
+ s.op->newline(1) << "sup->up.pid = tsk->tgid;";
+ s.op->newline() << "sup->up.vaddr = relocation + sups->address;";
s.op->newline() << "sup->up.handler = &enter_uprobe_probe;";
+ s.op->newline() << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uprobe register pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);";
+ s.op->newline() << "#endif";
s.op->newline() << "rc = register_uprobe (& sup->up);";
s.op->newline(-1) << "}";
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
- s.op->newline(1) << "struct stap_uprobe *sup2 = & stap_uprobes[j];";
- s.op->newline() << "if (sup2->return_p) unregister_uretprobe (&sup2->urp);";
- s.op->newline() << "else unregister_uprobe (&sup2->up);";
- // NB: we don't have to clear sup2->registered_p, since the module_exit code is
- // not run for this early-abort case.
+
+ s.op->newline() << "if (rc) {"; // failed to register
+ s.op->newline(1) << "printk (KERN_WARNING \"uprobe failed pid %d addr %p rc %d\\n\", tsk->tgid, (void*)(relocation + sups->address), rc);";
+ s.op->newline() << "sup->spec_index = -1;";
+ s.op->newline(-1) << "} else {";
+ s.op->newline(1) << "handled_p = 1;"; // success
s.op->newline(-1) << "}";
- s.op->newline() << "break;"; // don't attempt to register any more probes
+ s.op->newline() << "break;"; // exit free slot search whether or not handled_p
+
+ // unregister old uprobe
+ s.op->newline(-1) << "} else if (!register_p && "
+ << "sup->spec_index == spec_index && " // a u[ret]probe set up for this probe point
+ << "((sups->return_p && sup->urp.u.pid == tsk->tgid && sup->urp.u.vaddr == relocation + sups->address) ||" // dying uretprobe
+ << "(!sups->return_p && sup->up.pid == tsk->tgid && sup->up.vaddr == relocation + sups->address))) {"; // dying uprobe
+ s.op->newline() << "if (sups->return_p) {";
+ s.op->newline(1) << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "unregister_uretprobe (& sup->urp);";
+ s.op->newline(-1) << "} else {";
+ s.op->newline(1) << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uprobe unregister pid %d addr %p\\n\", sup->urp.u.pid, (void*) sup->urp.u.vaddr);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "unregister_uprobe (& sup->up);";
+ s.op->newline(-1) << "}";
+ s.op->newline(1) << "sup->spec_index = -1;";
+ s.op->newline() << "handled_p = 1;";
+ s.op->newline() << "break;"; // exit to-free slot search
+ s.op->newline(-1) << "}"; // if/else
+
+ s.op->newline(-1) << "}"; // stap_uprobes[] loop
+ s.op->newline() << "mutex_unlock (& stap_uprobes_lock);";
+ s.op->newline() << "if (! handled_p) {";
+ s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
+ s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ s.op->newline() << "_stp_exit ();";
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "return 0;"; // XXX: or rc?
s.op->newline(-1) << "}";
- s.op->newline() << "else sup->registered_p = 1;";
+ s.op->assert_0_indent();
+
+
+ // The task_finder_callback we use for ET_EXEC targets.
+ s.op->newline();
+ s.op->newline() << "static int stap_uprobe_process_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
+
+ s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);";
+ s.op->newline() << "if (! process_p) return 0;";
+ s.op->newline(0) << "return stap_uprobe_change (tsk, register_p, 0, sups);";
s.op->newline(-1) << "}";
+
+ // The task_finder_vm_callback we use for ET_DYN targets.
+ s.op->newline();
+ s.op->newline() << "static int stap_uprobe_vmchange_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, unsigned long vm_start, unsigned long vm_end, unsigned long vm_pgoff) {";
+ s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);";
+ // 1 - shared libraries' executable segments load from offset 0 - ld.so convention
+ s.op->newline() << "if (vm_pgoff != 0) return 0;";
+ // 2 - the shared library we're interested in
+ s.op->newline() << "if (vm_path == NULL || strcmp (vm_path, sups->pathname)) return 0;";
+ // 3 - probe address within the mapping limits; test should not fail
+ s.op->newline() << "if (vm_end <= vm_start + sups->address) return 0;";
+
+ s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
+ s.op->newline() << "printk (KERN_INFO \"vmchange pid %d map_p %d path %s vms %p vme %p vmp %p\\n\", tsk->tgid, map_p, vm_path, (void*) vm_start, (void*) vm_end, (void*) vm_pgoff);";
+ s.op->newline() << "printk (KERN_INFO \"sups %p pp %s path %s address %p\\n\", sups, sups->pp, sups->pathname ?: \"\", (void*) sups->address);";
+ s.op->newline() << "#endif";
+
+ s.op->newline(0) << "return stap_uprobe_change (tsk, map_p, vm_start, sups);";
+ s.op->newline(-1) << "}";
+ s.op->assert_0_indent();
+
+
+ s.op->newline();
}
void
-uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
+uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
if (probes.empty()) return;
s.op->newline() << "/* ---- user probes ---- */";
+ s.op->newline() << "for (j=0; j<NUMUPROBES; j++) {";
+ s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];";
+ s.op->newline() << "sup->spec_index = -1;"; // free slot
+ s.op->newline(-1) << "}";
+ s.op->newline() << "mutex_init (& stap_uprobes_lock);";
+
s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];";
- s.op->newline() << "if (! sup->registered_p) continue;";
- // s.op->newline() << "atomic_add (sdp->u.krp.nmissed, & skipped_count);";
- // s.op->newline() << "atomic_add (sdp->u.krp.kp.nmissed, & skipped_count);";
- s.op->newline() << "if (sup->return_p) unregister_uretprobe (&sup->urp);";
- s.op->newline() << "else unregister_uprobe (&sup->up);";
- s.op->newline() << "sup->registered_p = 0;";
+ s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];";
+ s.op->newline() << "probe_point = sups->pp;"; // for error messages
+ s.op->newline() << "if (sups->finder.pathname) sups->finder.callback = & stap_uprobe_process_found;";
+ s.op->newline() << "else if (sups->pathname) sups->finder.vm_callback = & stap_uprobe_vmchange_found;";
+ s.op->newline() << "rc = stap_register_task_finder_target (& sups->finder);";
+
+ // NB: if (rc), there is no need (XXX: nor any way) to clean up any
+ // finders already registered, since mere registration does not
+ // cause any utrace or memory allocation actions. That happens only
+ // later, once the task finder engine starts running. So, for a
+ // partial initialization requiring unwind, we need do nothing.
+ s.op->newline() << "if (rc) break;";
+
s.op->newline(-1) << "}";
}
+void
+uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty()) return;
+ s.op->newline() << "/* ---- user probes ---- */";
+
+ // NB: there is no stap_unregister_task_finder_target call;
+ // important stuff like utrace cleanups are done by
+ // __stp_task_finder_cleanup()
+
+ s.op->newline() << "for (j=0; j<NUMUPROBES; j++) {";
+ s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];";
+ s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];";
+ s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot
+
+ s.op->newline() << "if (sups->return_p) {";
+ s.op->newline(1) << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister2 index %d pid %d addr %p\\n\", sup->spec_index, sup->up.pid, (void*) sup->up.vaddr);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "unregister_uretprobe (& sup->urp);";
+ s.op->newline(-1) << "} else {";
+ s.op->newline(1) << "#ifdef DEBUG_UPROBES";
+ s.op->newline() << "printk (KERN_WARNING \"uprobe unregister2 index %d pid %d addr %p\\n\", sup->spec_index, sup->urp.u.pid, (void*) sup->urp.u.vaddr);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "unregister_uprobe (& sup->up);";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "sup->spec_index = -1;";
+
+ // XXX: uprobe missed counts?
+
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "mutex_destroy (& stap_uprobes_lock);";
+}
+
+
// ------------------------------------------------------------------------
// timer derived probes
@@ -8866,7 +9143,7 @@ register_standard_tapsets(systemtap_session & s)
s.pattern_root->bind("perfmon")->bind_str("counter")
->bind(new perfmon_builder());
- // dwarf-based kernel/module parts
+ // dwarf-based kprobe/uprobe parts
dwarf_derived_probe::register_patterns(s.pattern_root);
// XXX: user-space starter set
diff --git a/translate.cxx b/translate.cxx
index 57dfe4c3..2fe33314 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -4429,7 +4429,13 @@ dump_unwindsyms (Dwfl_Module *m,
else if (n > 0)
{
assert (secname != NULL);
- // secname adequately set
+ // secname adequately set
+
+ // NB: it may be an empty string for ET_DYN objects
+ // like shared libraries, as their relocation base
+ // is implicit.
+ if (secname[0] == '\0')
+ secname = ".dynamic";
}
else
{
@@ -4507,7 +4513,7 @@ emit_symbol_data (systemtap_session& s)
unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules };
- // XXX: copied from tapsets.cxx, sadly
+ // XXX: copied from tapsets.cxx dwflpp::, sadly
static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build";
static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
@@ -4546,6 +4552,7 @@ emit_symbol_data (systemtap_session& s)
// ---- step 2: process any user modules (files) listed
+ // XXX: see dwflpp::setup_user.
static const Dwfl_Callbacks user_callbacks =
{
NULL, /* dwfl_linux_kernel_find_elf, */
diff --git a/util.cxx b/util.cxx
index d57ef88c..a5f77c06 100644
--- a/util.cxx
+++ b/util.cxx
@@ -154,50 +154,69 @@ tokenize(const string& str, vector<string>& tokens,
}
-// Find an executable by name in $PATH.
-bool
-find_executable(const char *name, string& retpath)
+// Resolve an executable name to a canonical full path name, with the
+// same policy as execvp(). A program name not containing a slash
+// will be searched along the $PATH.
+
+string find_executable(const string& name)
{
- const char *p;
- string path;
- vector<string> dirs;
- struct stat st1, st2;
+ string retpath;
+
+ if (name.size() == 0)
+ return name;
+
+ struct stat st;
- if (*name == '/')
+ if (name.find('/') != string::npos) // slash in the path already?
{
retpath = name;
- return true;
+ }
+ else // Nope, search $PATH.
+ {
+ char *path = getenv("PATH");
+ if (path)
+ {
+ // Split PATH up.
+ vector<string> dirs;
+ tokenize(string(path), dirs, string(":"));
+
+ // Search the path looking for the first executable of the right name.
+ for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
+ {
+ string fname = *i + "/" + name;
+ const char *f = fname.c_str();
+
+ // Look for a normal executable file.
+ if (access(f, X_OK) == 0
+ && stat(f, &st) == 0
+ && S_ISREG(st.st_mode))
+ {
+ retpath = fname;
+ break;
+ }
+ }
+ }
}
- p = getenv("PATH");
- if (!p)
- return false;
- path = p;
- // Split PATH up.
- tokenize(path, dirs, string(":"));
+ // Could not find the program on the $PATH. We'll just fall back to
+ // the unqualified name, which our caller will probably fail with.
+ if (retpath == "")
+ retpath = name;
- // Search the path looking for the first executable of the right name.
- for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
+ // Canonicalize the path name.
+ char *cf = canonicalize_file_name (retpath.c_str());
+ if (cf)
{
- string fname = *i + "/" + name;
- const char *f = fname.c_str();
-
- // Look for a normal executable file.
- if (access(f, X_OK) == 0
- && lstat(f, &st1) == 0
- && stat(f, &st2) == 0
- && S_ISREG(st2.st_mode))
- {
- // Found it!
- retpath = fname;
- return true;
- }
+ retpath = string(cf);
+ free (cf);
}
- return false;
+ return retpath;
}
+
+
const string cmdstr_quoted(const string& cmd)
{
// original cmd : substr1
diff --git a/util.h b/util.h
index 735652eb..6c69c998 100644
--- a/util.h
+++ b/util.h
@@ -10,7 +10,7 @@ int copy_file(const char *src, const char *dest);
int create_dir(const char *dir);
void tokenize(const std::string& str, std::vector<std::string>& tokens,
const std::string& delimiters);
-bool find_executable(const char *name, std::string& retpath);
+std::string find_executable(const std::string& name);
const std::string cmdstr_quoted(const std::string& cmd);