summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--runtime/ChangeLog11
-rw-r--r--runtime/runtime.h18
-rw-r--r--runtime/sym.c32
-rw-r--r--runtime/task_finder.c22
-rw-r--r--runtime/task_finder_vma.c38
-rw-r--r--tapset/ChangeLog7
-rw-r--r--tapset/context-symbols.stp8
-rw-r--r--tapset/context-unwind.stp3
-rw-r--r--tapsets.cxx4
-rw-r--r--testsuite/ChangeLog5
-rw-r--r--testsuite/systemtap.context/usymbols.c41
-rw-r--r--testsuite/systemtap.context/usymbols.exp69
13 files changed, 238 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 6b31fb76..c46c0ef2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-12-10 Mark Wielaard <mjw@redhat.com>
+
+ * tapsets.cxx
+ (utrace_derived_probe_group::emit_vm_callback_probe_decl):
+ Test for STP_NEED_TASK_FINDER_VMA to enable
+ emit_vm_callback_probe_decl.
+
2008-12-09 Frank Ch. Eigler <fche@elastic.org>
PR6961
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 3f88bae2..d83ac12c 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,14 @@
+2008-12-10 Mark Wielaard <mjw@redhat.com>
+
+ * runtime.h: Define __stp_tf_vma_entry here.
+ * sym.c (_stp_mod_sec_lookup): Try vma matching first if task given.
+ (_stp_kallsyms_lookup): Take an optional task.
+ (_stp_symbol_snprint): Likewise.
+ task_finder.c (__stp_tf_vm_cb): Use vm_path to match and attach
+ module to vma entry.
+ task_finder_vma.c (stap_add_vma_map_info): Take an optional module.
+ (__stp_tf_get_vma_entry_addr): New lookup function.
+
2008-12-09 Frank Ch. Eigler <fche@elastic.org>
* time.c (_stp_gettimeofday_ns): Protect some more against freq=0.
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3b3e117d..055d3f27 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -86,6 +86,24 @@ static struct
#include "io.c"
#include "arith.c"
#include "copy.c"
+
+/* Lifted task_finder, internal details used in sym.c - XXX */
+struct __stp_tf_vma_entry {
+ struct hlist_node hlist;
+
+ pid_t pid;
+ unsigned long addr;
+ unsigned long vm_start;
+ unsigned long vm_end;
+ unsigned long vm_pgoff;
+ // Is that enough? Should we store a dcookie for vm_file?
+
+ // Module that this vma entry is mapped from, if any.
+ struct _stp_module *module;
+};
+static struct __stp_tf_vma_entry *
+__stp_tf_get_vma_entry_addr(struct task_struct *, unsigned long);
+
#include "sym.c"
#ifdef STP_PERFMON
#include "perf.c"
diff --git a/runtime/sym.c b/runtime/sym.c
index 06ac14a5..9b295f58 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -77,11 +77,28 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
if found, return NULL otherwise.
XXX: needs to be address-space-specific. */
static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
+ struct task_struct *task,
struct _stp_section **sec)
{
struct _stp_module *m = NULL;
unsigned midx = 0;
unsigned long closest_section_offset = ~0;
+
+ // Try vma matching first if task given.
+ struct __stp_tf_vma_entry *entry;
+ if (task)
+ {
+ entry = __stp_tf_get_vma_entry_addr(task, addr);
+ if (entry != NULL && entry->module != NULL)
+ {
+ m = entry->module;
+ *sec = & m->sections[0]; // XXX check actual section and relocate
+ if (strcmp(".dynamic", m->sections[0].name) == 0)
+ m->sections[0].addr = entry->vm_start; // cheat...
+ return m;
+ }
+ }
+
for (midx = 0; midx < _stp_num_modules; midx++)
{
unsigned secidx;
@@ -109,7 +126,8 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo
unsigned long *offset,
const char **modname,
/* char ** secname? */
- char *namebuf)
+ char *namebuf,
+ struct task_struct *task)
{
struct _stp_module *m = NULL;
struct _stp_section *sec = NULL;
@@ -117,7 +135,7 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo
unsigned long flags;
unsigned end, begin = 0;
- m = _stp_mod_sec_lookup(addr, &sec);
+ m = _stp_mod_sec_lookup(addr, task, &sec);
if (unlikely (m == NULL || sec == NULL))
return NULL;
@@ -242,7 +260,7 @@ void _stp_symbol_print(unsigned long address)
const char *name;
unsigned long offset, size;
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, NULL);
_stp_printf("%p", (int64_t) address);
@@ -267,7 +285,7 @@ int _stp_func_print(unsigned long address, int verbose, int exact)
else
exstr = " (inexact)";
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, NULL);
if (name) {
if (verbose) {
@@ -283,13 +301,15 @@ int _stp_func_print(unsigned long address, int verbose, int exact)
return 0;
}
-void _stp_symbol_snprint(char *str, size_t len, unsigned long address)
+void _stp_symbol_snprint(char *str, size_t len, unsigned long address,
+ struct task_struct *task)
{
const char *modname;
const char *name;
unsigned long offset, size;
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL,
+ task);
if (name)
strlcpy(str, name, len);
else
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 25fad1a4..1e0a8474 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -55,7 +55,6 @@ typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt,
unsigned long vm_end,
unsigned long vm_pgoff);
-#ifdef DEBUG_TASK_FINDER_VMA
int __stp_tf_vm_cb(struct stap_task_finder_target *tgt,
struct task_struct *tsk,
int map_p, char *vm_path,
@@ -63,21 +62,32 @@ int __stp_tf_vm_cb(struct stap_task_finder_target *tgt,
unsigned long vm_end,
unsigned long vm_pgoff)
{
+ int i;
+#ifdef DEBUG_TASK_FINDER_VMA
_stp_dbug(__FUNCTION__, __LINE__,
"vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n",
tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff);
+#endif
if (map_p) {
- // FIXME: What should we do with vm_path? We can't save
- // the vm_path pointer itself, but we don't have any
- // storage space allocated to save it in...
- stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff);
+ struct _stp_module *module = NULL;
+ if (vm_path != NULL)
+ for (i = 0; i < _stp_num_modules; i++)
+ if (strcmp(vm_path, _stp_modules[i]->name) == 0)
+ {
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "vm_cb: matched path %s to module\n", vm_path);
+#endif
+ module = _stp_modules[i];
+ break;
+ }
+ stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff, module);
}
else {
stap_remove_vma_map_info(tsk, vm_start, vm_end, vm_pgoff);
}
return 0;
}
-#endif
struct stap_task_finder_target {
/* private: */
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index 4dce4be8..b65d9ea4 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -16,17 +16,6 @@ static DEFINE_MUTEX(__stp_tf_vma_mutex);
#define TASK_FINDER_VMA_ENTRY_ITEMS 100
#endif
-struct __stp_tf_vma_entry {
- struct hlist_node hlist;
-
- pid_t pid;
- unsigned long addr;
- unsigned long vm_start;
- unsigned long vm_end;
- unsigned long vm_pgoff;
- // Is that enough? Should we store a dcookie for vm_file?
-};
-
static struct __stp_tf_vma_entry
__stp_tf_vma_free_list_items[TASK_FINDER_VMA_ENTRY_ITEMS];
@@ -211,7 +200,8 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
// Add the vma info to the vma map hash table.
static int
stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
- unsigned long vm_end, unsigned long vm_pgoff)
+ unsigned long vm_end, unsigned long vm_pgoff,
+ struct _stp_module *module)
{
struct hlist_head *head;
struct hlist_node *node;
@@ -242,6 +232,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
entry->vm_start = vm_start;
entry->vm_end = vm_end;
entry->vm_pgoff = vm_pgoff;
+ entry->module = module;
head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
hlist_add_head(&entry->hlist, head);
@@ -305,3 +296,26 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
mutex_unlock(&__stp_tf_vma_mutex);
return rc;
}
+
+// Get vma_entry of the address (vm_start/vm_end) if the vma is
+// present in the vma hash table containing.
+// Returns NULL if not present.
+static struct __stp_tf_vma_entry *
+__stp_tf_get_vma_entry_addr(struct task_struct *tsk, unsigned long addr)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct __stp_tf_vma_entry *entry;
+
+ mutex_lock(&__stp_tf_vma_mutex);
+ head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
+ hlist_for_each_entry(entry, node, head, hlist) {
+ if (tsk->pid == entry->pid
+ && addr >= entry->vm_start && addr < entry->vm_end) {
+ mutex_unlock(&__stp_tf_vma_mutex);
+ return entry;
+ }
+ }
+ mutex_unlock(&__stp_tf_vma_mutex);
+ return NULL;
+}
diff --git a/tapset/ChangeLog b/tapset/ChangeLog
index 626ad67b..30634bcc 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,10 @@
+2008-12-10 Mark Wielaard <mjw@redhat.com>
+
+ * context-symbols.stp: Define STP_NEED_TASK_FINDER_VMA.
+ (symbolname): New function.
+ * context-unwind.stp (caller): Pass current task to
+ _stp_symbol_snprint.
+
2008-12-09 Frank Ch. Eigler <fche@elastic.org>
PR 6961.
diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp
index 79645f4f..fbb51767 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -11,6 +11,9 @@
#ifndef STP_NEED_SYMBOL_DATA
#define STP_NEED_SYMBOL_DATA 1
#endif
+#ifndef STP_NEED_TASK_FINDER_VMA
+#define STP_NEED_TASK_FINDER_VMA 1
+#endif
%}
/**
@@ -93,3 +96,8 @@ function probemod:string () %{ /* pure */
THIS->__retvalue[0] = '\0';
}
%}
+
+function symbolname:string (addr:long) %{ /* pure */
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
+ current);
+%}
diff --git a/tapset/context-unwind.stp b/tapset/context-unwind.stp
index 4c5ed34b..59d111ee 100644
--- a/tapset/context-unwind.stp
+++ b/tapset/context-unwind.stp
@@ -51,7 +51,8 @@ function backtrace:string () %{ /* pure */
function caller:string() %{ /* pure */
if (CONTEXT->pi)
_stp_symbol_snprint( THIS->__retvalue, MAXSTRINGLEN,
- (unsigned long)_stp_ret_addr_r(CONTEXT->pi));
+ (unsigned long)_stp_ret_addr_r(CONTEXT->pi),
+ current);
else
strlcpy(THIS->__retvalue,"unknown",MAXSTRINGLEN);
%}
diff --git a/tapsets.cxx b/tapsets.cxx
index 4d9a021d..9fe1d236 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -6800,7 +6800,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
// Emit a "fake" probe decl that is really a hook for to get
// our vm_callback called.
string path = it->first;
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
+ s.op->newline() << "#ifdef STP_NEED_TASK_FINDER_VMA";
emit_vm_callback_probe_decl (s, true, path, (int64_t)0,
"__stp_tf_vm_cb");
s.op->newline() << "#endif";
@@ -6821,7 +6821,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
{
// Emit a "fake" probe decl that is really a hook for to get
// our vm_callback called.
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
+ s.op->newline() << "#ifdef STP_NEED_TASK_FINDER_VMA";
emit_vm_callback_probe_decl (s, false, "", it->first,
"__stp_tf_vm_cb");
s.op->newline() << "#endif";
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index 8e174efc..44261176 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-12-10 Mark Wielaard <mjw@redhat.com>
+
+ * systemtap.context/usymbols.c: New test program.
+ * systemtap.context/usymbols.exp: New dejagnu test.
+
2008-12-09 Frank Ch. Eigler <fche@elastic.org>
PR6961.
diff --git a/testsuite/systemtap.context/usymbols.c b/testsuite/systemtap.context/usymbols.c
new file mode 100644
index 00000000..f8ee05b5
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.c
@@ -0,0 +1,41 @@
+/* usymbol test case
+ * Copyright (C) 2008, Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ *
+ * Uses signal to tranfer user space addresses into the kernel where a
+ * probe on sigaction will extract them and produce the symbols. To
+ * poke into the executable we get the sa_handler, to poke into glibc
+ * we get the sa_restorer fields in the stap script.
+ *
+ * XXX - Seems sa_restorer isn't set on all architectures. should use
+ * our own shared library and set signal handler from there. Also
+ * need to handle @plt symbols (setting a handler in the main
+ * executable that is in a shared library will have the @plt address,
+ * not the address inside the shared library).
+ */
+
+#include <signal.h>
+typedef void (*sighandler_t)(int);
+
+void
+handler (int signum)
+{
+ /* dummy handler, just used for the address... */
+}
+
+sighandler_t
+libc_handler (void *func)
+{
+ return (sighandler_t) func;
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ // Use SIGFPE since we never expect that to be triggered.
+ signal(SIGFPE, handler);
+}
diff --git a/testsuite/systemtap.context/usymbols.exp b/testsuite/systemtap.context/usymbols.exp
new file mode 100644
index 00000000..ebaa058e
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.exp
@@ -0,0 +1,69 @@
+set test "./usymbols"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/usymbols.c"
+set testexe "[pwd]/usymbols"
+set testflags "additional_flags=-g additional_flags=-O"
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test -p5"; return }
+
+# Compile out test program
+set res [target_compile $testsrc $testexe executable $testflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "unable to compile $testsrc"
+ return
+}
+
+# We need the execname() trick to work around (the workaround of) PR6964
+# otherwise we get also the rt_sigactions of stapio. Get the handler
+# (comes from the executable) and the restorer (comes from glibc).
+set testscript {
+ probe syscall.rt_sigaction {
+ if (pid() == target() && execname() == "%s") {
+ handler = $act->sa_handler;
+ printf("handler: %%s\n", symbolname(handler));
+ restorer = $act->sa_restorer;
+ printf("restorer: %%s\n", symbolname(restorer));
+ }
+ }
+ probe process("%s").syscall { printf(""); /* XXX trigger tracker */ }
+}
+
+set output {handler: handler
+restorer: __restore_rt}
+
+# Got to run stap with both the exe and the libraries used as -d args.
+# XXX Note how we need the fully resolved (absolute) path...
+set script [format $testscript usymbols $testexe]
+catch {eval exec [concat ldd $testexe | grep libc.so]} libc
+set libc [lindex [split $libc " "] 2]
+send_log "libc: $libc\n"
+if {[string equal "link" [file type $libc]]} {
+ set libc [file join [file dirname $libc] [file readlink $libc]]
+}
+send_log "libc: $libc\n"
+set cmd [concat stap -d $libc -d $testexe -c $testexe -e {$script}]
+send_log "cmd: $cmd\n"
+catch {eval exec $cmd} res
+send_log "cmd output: $res\n"
+
+set n 0
+set m [llength [split $output "\n"]]
+set expected [split $output "\n"]
+foreach line [split $res "\n"] {
+ if {![string equal $line [lindex $expected $n]]} {
+ fail usymbols
+ send_log "line [expr $n + 1]: expected \"[lindex $expected $n]\", "
+ send_log "Got \"$line\"\n"
+ return
+ }
+ incr n
+}
+if { $n != $m } {
+ fail usymbols
+ send_log "Got \"$n\" lines, expected \"$m\" lines\n"
+} else {
+ pass usymbols
+}
+exec rm -f $testexe