summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buildrun.cxx8
-rw-r--r--main.cxx77
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/sym.c71
-rw-r--r--runtime/task_finder.c34
-rw-r--r--runtime/task_finder_vma.c110
-rw-r--r--tapset/context-symbols.stp7
-rw-r--r--tapset/context-unwind.stp3
-rw-r--r--tapset/i686/syscalls.stp2
-rw-r--r--tapsets.cxx169
-rw-r--r--testsuite/lib/stap_run.exp1
-rw-r--r--testsuite/lib/systemtap.exp10
-rwxr-xr-xtestsuite/systemtap.base/bz5274.exp9
-rw-r--r--testsuite/systemtap.base/bz6850.exp9
-rw-r--r--testsuite/systemtap.base/itrace.exp42
-rw-r--r--testsuite/systemtap.base/labels.exp10
-rw-r--r--testsuite/systemtap.base/static_uprobes.exp10
-rw-r--r--testsuite/systemtap.base/uprobes.exp9
-rw-r--r--testsuite/systemtap.base/uprobes_lib.exp15
-rw-r--r--testsuite/systemtap.base/utrace_p4.exp34
-rw-r--r--testsuite/systemtap.base/utrace_p5.exp21
-rw-r--r--testsuite/systemtap.context/usymbols.c39
-rw-r--r--testsuite/systemtap.context/usymbols.exp82
-rw-r--r--testsuite/systemtap.context/usymbols_lib.c29
-rw-r--r--testsuite/systemtap.pass1-4/buildok.exp1
-rw-r--r--util.cxx41
-rw-r--r--util.h2
27 files changed, 526 insertions, 322 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index 97357692..71a34c96 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -56,7 +56,7 @@ run_make_cmd(systemtap_session& s, string& make_cmd)
make_cmd += " -s >/dev/null 2>&1";
if (s.verbose > 1) clog << "Running " << make_cmd << endl;
- rc = system (make_cmd.c_str());
+ rc = stap_system (make_cmd.c_str());
return rc;
}
@@ -223,7 +223,7 @@ kernel_built_uprobes (systemtap_session& s)
{
string grep_cmd = string ("/bin/grep -q unregister_uprobe ") +
s.kernel_build_tree + string ("/Module.symvers");
- int rc = system (grep_cmd.c_str());
+ int rc = stap_system (grep_cmd.c_str());
return (rc == 0);
}
@@ -274,7 +274,7 @@ copy_uprobes_symbols (systemtap_session& s)
string uprobes_home = s.runtime_path + "/uprobes";
string cp_cmd = string("/bin/cp ") + uprobes_home +
string("/Module.symvers ") + s.tmpdir;
- int rc = system (cp_cmd.c_str());
+ int rc = stap_system (cp_cmd.c_str());
return rc;
}
@@ -339,7 +339,7 @@ run_pass (systemtap_session& s)
if (s.verbose>1) clog << "Running " << staprun_cmd << endl;
- rc = system (staprun_cmd.c_str ());
+ rc = stap_system (staprun_cmd.c_str ());
return rc;
}
diff --git a/main.cxx b/main.cxx
index 3b88a1c8..794a5891 100644
--- a/main.cxx
+++ b/main.cxx
@@ -36,8 +36,6 @@ extern "C" {
#include <sys/times.h>
#include <sys/time.h>
#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
#include <time.h>
#include <elfutils/libdwfl.h>
#include <getopt.h>
@@ -293,14 +291,9 @@ int pending_interrupts;
extern "C"
void handle_interrupt (int sig)
{
- if (pending_interrupts == 0)
- kill (0, sig); // Forward signals to child processes if any.
-
+ kill_stap_spawn(sig);
pending_interrupts ++;
- // NB: the "2" below is intended to skip the effect of the self-induced
- // deferred signal coming from the kill() above.
-
- if (pending_interrupts > 2) // XXX: should be configurable? time-based?
+ if (pending_interrupts > 1) // XXX: should be configurable? time-based?
{
char msg[] = "Too many interrupts received, exiting.\n";
int rc = write (2, msg, sizeof(msg)-1);
@@ -324,7 +317,7 @@ setup_signals (sighandler_t handler)
sigaddset (&sa.sa_mask, SIGINT);
sigaddset (&sa.sa_mask, SIGTERM);
}
- sa.sa_flags = 0;
+ sa.sa_flags = SA_RESTART;
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGPIPE, &sa, NULL);
@@ -332,62 +325,10 @@ setup_signals (sighandler_t handler)
sigaction (SIGTERM, &sa, NULL);
}
-pid_t runner_pid;
-int runner (int, char * const []);
-
-// Passes on signals to runner process.
-// In practise passes signal to runner process process group,
-// since run_pass() uses system() to spawn child processes,
-// which makes the process ignore SIGINT during the command run.
-extern "C"
-void waiter_handler (int sig)
-{
- // Process group is negative process id.
- kill (-1 * runner_pid, sig);
-}
-
-// Just sits there till the runner exits and then exits the same way.
-void waiter()
-{
- int status;
- setup_signals (&waiter_handler);
- while (waitpid (runner_pid, &status, 0) != runner_pid);
-
- // Exit as our runner child exitted.
- if (WIFEXITED(status))
- exit (WEXITSTATUS(status));
-
- // Or simulate as if we were killed by the same signal.
- if (WIFSIGNALED(status))
- {
- int sig = WTERMSIG(status);
- signal (sig, SIG_DFL);
- raise (sig);
- }
-
- // Should not happen, exit as if error.
- exit(-1);
-}
int
main (int argc, char * const argv [])
{
- // Fork to make sure runner gets its own process group, while
- // the waiter sits in the original process group of the shell
- // and forwards any signals.
- runner_pid = fork ();
- if (runner_pid == 0)
- return runner (argc, argv);
- if (runner_pid > 0)
- waiter ();
-
- perror ("couldn't fork");
- exit (-1);
-}
-
-int
-runner (int argc, char * const argv [])
-{
string cmdline_script; // -e PROGRAM
string script_file; // FILE
bool have_script = false;
@@ -899,16 +840,6 @@ runner (int argc, char * const argv [])
// directory.
s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
- // We want a new process group so we can use kill (0, sig) to send a
- // signal to all children (but not the parent). As done in
- // handle_interrupt ().
- if (setpgrp() != 0)
- {
- const char* e = strerror (errno);
- if (! s.suppress_warnings)
- cerr << "Warning: failed to set new process group: " << e << endl;
- }
-
// Set up our handler to catch routine signals, to allow clean
// and reasonably timely exit.
setup_signals(&handle_interrupt);
@@ -1251,7 +1182,7 @@ pass_5:
string cleanupcmd = "rm -rf ";
cleanupcmd += s.tmpdir;
if (s.verbose>1) clog << "Running " << cleanupcmd << endl;
- int status = system (cleanupcmd.c_str());
+ int status = stap_system (cleanupcmd.c_str());
if (status != 0 && s.verbose>1)
clog << "Cleanup command failed, status: " << status << endl;
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index fc5d454f..822562a2 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -86,6 +86,9 @@ static struct
#include "io.c"
#include "arith.c"
#include "copy.c"
+
+#include "task_finder.c"
+
#include "sym.c"
#ifdef STP_PERFMON
#include "perf.c"
diff --git a/runtime/sym.c b/runtime/sym.c
index 1d88a862..d0c5d9fd 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -20,6 +20,40 @@
* @{
*/
+/* Callback that needs to be registered (in tapsets.cxx for
+ emit_module_init) for every user task path or pid for which we
+ might need symbols or unwind info. */
+static int _stp_tf_vm_cb(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)
+{
+ 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)
+ {
+ struct _stp_module *module = NULL;
+ if (vm_path != NULL)
+ for (i = 0; i < _stp_num_modules; i++)
+ if (strcmp(vm_path, _stp_modules[i]->path) == 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;
+}
+
/* XXX: this needs to be address-space-specific. */
static unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset)
{
@@ -76,11 +110,33 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
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)
{
+ void *user = NULL;
struct _stp_module *m = NULL;
unsigned midx = 0;
unsigned long closest_section_offset = ~0;
+
+ // Try vma matching first if task given.
+ if (task)
+ {
+ unsigned long vm_start = 0;
+ if (stap_find_vma_map_info(task, addr,
+ &vm_start, NULL,
+ NULL, &user) == 0)
+ if (user != NULL)
+ {
+ m = (struct _stp_module *)user;
+ *sec = &m->sections[0]; // XXX check actual section and relocate
+ dbug_sym(1, "found section %s in module %s at 0x%lx\n",
+ m->sections[0].name, m->name, vm_start);
+ if (strcmp(".dynamic", m->sections[0].name) == 0)
+ m->sections[0].addr = vm_start; // cheat...
+ return m;
+ }
+ }
+
for (midx = 0; midx < _stp_num_modules; midx++)
{
unsigned secidx;
@@ -108,14 +164,15 @@ 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;
struct _stp_symbol *s = NULL;
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;
@@ -240,7 +297,7 @@ static 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);
@@ -265,7 +322,7 @@ static 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) {
@@ -281,13 +338,15 @@ static int _stp_func_print(unsigned long address, int verbose, int exact)
return 0;
}
-static void _stp_symbol_snprint(char *str, size_t len, unsigned long address)
+static 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 7949a81f..44dca296 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -69,40 +69,6 @@ typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt,
unsigned long vm_end,
unsigned long vm_pgoff);
-static int __stp_tf_vm_cb(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)
-{
- 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) {
- struct _stp_module *module = NULL;
- if (vm_path != NULL)
- for (i = 0; i < _stp_num_modules; i++)
- if (strcmp(vm_path, _stp_modules[i]->path) == 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;
-}
-
struct stap_task_finder_target {
/* private: */
struct list_head list; /* __stp_task_finder_list linkage */
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index 83b206e5..ed9c6f4f 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -1,13 +1,19 @@
#include <linux/list.h>
#include <linux/jhash.h>
-#include <linux/mutex.h>
+#include <linux/spinlock.h>
// When handling memcpy() syscall tracing to notice memory map
// changes, we need to cache memcpy() entry parameter values for
// processing at memcpy() exit.
-// __stp_tf_vma_mutex protects the hash table.
-static DEFINE_MUTEX(__stp_tf_vma_mutex);
+// __stp_tf_vma_lock protects the hash table.
+// Documentation/spinlocks.txt suggest we can be a bit more clever
+// if we guarantee that in interrupt context we only read, not write
+// the datastructures. We should never change the hash table or the
+// contents in interrupt context (which should only ever call
+// stap_find_vma_map_info for getting stored vma info). So we might
+// want to look into that if this seems a bottleneck.
+static DEFINE_RWLOCK(__stp_tf_vma_lock);
#define __STP_TF_HASH_BITS 4
#define __STP_TF_TABLE_SIZE (1 << __STP_TF_HASH_BITS)
@@ -26,8 +32,8 @@ struct __stp_tf_vma_entry {
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;
+ // User data (possibly stp_module)
+ void *user;
};
static struct __stp_tf_vma_entry
@@ -40,23 +46,24 @@ static struct hlist_head __stp_tf_vma_table[__STP_TF_TABLE_SIZE];
static struct hlist_head __stp_tf_vma_map[__STP_TF_TABLE_SIZE];
// __stp_tf_vma_initialize(): Initialize the free list. Grabs the
-// mutex.
+// spinlock.
static void
__stp_tf_vma_initialize(void)
{
int i;
struct hlist_head *head = &__stp_tf_vma_free_list[0];
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
for (i = 0; i < TASK_FINDER_VMA_ENTRY_ITEMS; i++) {
hlist_add_head(&__stp_tf_vma_free_list_items[i].hlist, head);
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
}
// __stp_tf_vma_get_free_entry(): Returns an entry from the free list
-// or NULL. The __stp_tf_vma_mutex must be locked before calling this
+// or NULL. The __stp_tf_vma_lock must be write locked before calling this
// function.
static struct __stp_tf_vma_entry *
__stp_tf_vma_get_free_entry(void)
@@ -77,7 +84,7 @@ __stp_tf_vma_get_free_entry(void)
// __stp_tf_vma_put_free_entry(): Puts an entry back on the free
-// list. The __stp_tf_vma_mutex must be locked before calling this
+// list. The __stp_tf_vma_lock must be write locked before calling this
// function.
static void
__stp_tf_vma_put_free_entry(struct __stp_tf_vma_entry *entry)
@@ -101,7 +108,7 @@ __stp_tf_vma_hash(struct task_struct *tsk, unsigned long addr)
// Get vma_entry if the vma is present in the vma hash table.
-// Returns NULL if not present.
+// Returns NULL if not present. Takes a read lock on __stp_tf_vma_lock.
static struct __stp_tf_vma_entry *
__stp_tf_get_vma_entry(struct task_struct *tsk, unsigned long addr)
{
@@ -109,20 +116,22 @@ __stp_tf_get_vma_entry(struct task_struct *tsk, unsigned long addr)
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
&& addr == entry->addr) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return entry;
}
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return NULL;
}
// Add the vma info to the vma hash table.
+// Takes a write lock on __stp_tf_vma_lock.
static int
__stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
struct vm_area_struct *vma)
@@ -131,7 +140,8 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
@@ -141,7 +151,7 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
"vma (pid: %d, vm_start: 0x%lx) present?\n",
tsk->pid, vma->vm_start);
#endif
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -EBUSY; /* Already there */
}
}
@@ -149,7 +159,7 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
// Get an element from the free list.
entry = __stp_tf_vma_get_free_entry();
if (!entry) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -ENOMEM;
}
entry->pid = tsk->pid;
@@ -158,11 +168,12 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
entry->vm_end = vma->vm_end;
entry->vm_pgoff = vma->vm_pgoff;
hlist_add_head(&entry->hlist, head);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
// Remove the vma entry from the vma hash table.
+// Takes a write lock on __stp_tf_vma_lock.
static int
__stp_tf_remove_vma_entry(struct __stp_tf_vma_entry *entry)
{
@@ -171,10 +182,11 @@ __stp_tf_remove_vma_entry(struct __stp_tf_vma_entry *entry)
int found = 0;
if (entry != NULL) {
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
}
return 0;
}
@@ -189,7 +201,7 @@ __stp_tf_vma_map_hash(struct task_struct *tsk)
}
// Get vma_entry if the vma is present in the vma map hash table.
-// Returns NULL if not present. The __stp_tf_vma_mutex must be locked
+// Returns NULL if not present. The __stp_tf_vma_lock must be read locked
// before calling this function.
static struct __stp_tf_vma_entry *
__stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
@@ -214,13 +226,16 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
static int
stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
unsigned long vm_end, unsigned long vm_pgoff,
- struct _stp_module *module)
+ void *user)
{
struct hlist_head *head;
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ // Take a write lock, since we are most likely going to write
+ // after reading.
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
entry = __stp_tf_get_vma_map_entry_internal(tsk, vm_start);
if (entry != NULL) {
#if 0
@@ -228,14 +243,14 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
"vma (pid: %d, vm_start: 0x%lx) present?\n",
tsk->pid, entry->vm_start);
#endif
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -EBUSY; /* Already there */
}
// Get an element from the free list.
entry = __stp_tf_vma_get_free_entry();
if (!entry) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -ENOMEM;
}
@@ -245,11 +260,11 @@ 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;
+ entry->user = user;
head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
hlist_add_head(&entry->hlist, head);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
@@ -263,23 +278,26 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ // Take a write lock since we are most likely going to delete
+ // after reading.
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
entry = __stp_tf_get_vma_map_entry_internal(tsk, vm_start);
if (entry != NULL) {
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
// Finds vma info if the vma is present in the vma map hash table.
-// Returns ESRCH if not present. The __stp_tf_vma_mutex must *not* be
+// Returns ESRCH if not present. The __stp_tf_vma_lock must *not* be
// locked before calling this function.
static int
stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
unsigned long *vm_start, unsigned long *vm_end,
- unsigned long *vm_pgoff)
+ unsigned long *vm_pgoff, void **user)
{
struct hlist_head *head;
struct hlist_node *node;
@@ -287,7 +305,8 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
struct __stp_tf_vma_entry *found_entry = NULL;
int rc = ESRCH;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
@@ -304,31 +323,10 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
*vm_end = found_entry->vm_end;
if (vm_pgoff != NULL)
*vm_pgoff = found_entry->vm_pgoff;
+ if (user != NULL)
+ *user = found_entry->user;
rc = 0;
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
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/context-symbols.stp b/tapset/context-symbols.stp
index a3aae408..4c200aa8 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -66,7 +66,7 @@ function probefunc:string () %{ /* pure */
#else
((unsigned long)REG_IP(CONTEXT->regs) >= (unsigned long)PAGE_OFFSET)) {
#endif
- _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, REG_IP(CONTEXT->regs));
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, REG_IP(CONTEXT->regs), current);
if (THIS->__retvalue[0] == '.') /* powerpc symbol has a dot*/
strlcpy(THIS->__retvalue,THIS->__retvalue + 1,MAXSTRINGLEN);
} else {
@@ -94,3 +94,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 90d4e0f4..a976f8b6 100644
--- a/tapset/context-unwind.stp
+++ b/tapset/context-unwind.stp
@@ -56,7 +56,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/tapset/i686/syscalls.stp b/tapset/i686/syscalls.stp
index 8e69f622..2a89c19d 100644
--- a/tapset/i686/syscalls.stp
+++ b/tapset/i686/syscalls.stp
@@ -119,7 +119,7 @@ probe syscall.set_zone_reclaim.return =
#
probe syscall.sigaltstack = kernel.function("sys_sigaltstack") {
name = "sigaltstack"
- ussp = %( kernel_vr < "2.6.25" %? $ebx %: $bx %)
+ ussp = %( kernel_vr < "2.6.25" %? $ebx %: %( kernel_vr < "2.6.29" %? $bx %: $regs->bx %) %)
argstr = sprintf("%p", ussp)
}
probe syscall.sigaltstack.return = kernel.function("sys_sigaltstack").return {
diff --git a/tapsets.cxx b/tapsets.cxx
index 449d7cc0..1b55684b 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -6230,6 +6230,27 @@ module_info::~module_info()
delete sym_table;
}
+// Helper function to emit vma tracker callback _stp_tf_vm_cb.
+static void
+emit_vma_callback_probe_decl (systemtap_session& s,
+ string path,
+ int64_t pid)
+{
+ s.op->newline() << "{";
+ if (pid == 0)
+ {
+ s.op->line() << " .pathname=\"" << path << "\",";
+ s.op->line() << " .pid=0,";
+ }
+ else
+ {
+ s.op->line() << " .pathname=NULL,";
+ s.op->line() << " .pid=" << pid << ",";
+ }
+ s.op->line() << " .callback=NULL,";
+ s.op->line() << " .vm_callback=&_stp_tf_vm_cb,";
+ s.op->line() << " },";
+}
// ------------------------------------------------------------------------
@@ -6433,7 +6454,6 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "/* ---- itrace probes ---- */";
- s.op->newline() << "#include \"task_finder.c\"";
s.op->newline() << "struct stap_itrace_probe {";
s.op->indent(1);
s.op->newline() << "struct stap_task_finder_target tgt;";
@@ -6475,6 +6495,25 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "return rc;";
s.op->newline(-1) << "}";
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_itrace_vmcbs[] = {";
+ s.op->indent(1);
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
+ }
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ emit_vma_callback_probe_decl (s, "", it->first);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
s.op->indent(1);
@@ -6516,11 +6555,37 @@ itrace_derived_probe_group::emit_module_init (systemtap_session& s)
return;
s.op->newline();
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "/* ---- itrace vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_itrace_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_itrace_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
+ s.op->newline();
s.op->newline() << "/* ---- itrace probes ---- */";
s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
s.op->indent(1);
s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
+
+ // 'arch_has_single_step' needs to be defined for either single step mode
+ // or branch mode.
+ s.op->newline() << "if (!arch_has_single_step()) {";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");";
+ s.op->newline() << "rc = -EPERM;";
+ s.op->newline() << "break;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");";
+ s.op->newline() << "rc = -EPERM;";
+ s.op->newline() << "break;";
+ s.op->newline(-1) << "}";
+
s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
s.op->newline(-1) << "}";
}
@@ -6581,9 +6646,6 @@ private:
bool flags_seen[UDPF_NFLAGS];
void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p);
- void emit_vm_callback_probe_decl (systemtap_session& s, bool has_path,
- string path, int64_t pid,
- string vm_callback);
public:
utrace_derived_probe_group(): num_probes(0), flags_seen() { }
@@ -6965,40 +7027,6 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
void
-utrace_derived_probe_group::emit_vm_callback_probe_decl (systemtap_session& s,
- bool has_path,
- string path,
- int64_t pid,
- string vm_callback)
-{
- s.op->newline() << "{";
- s.op->line() << " .tgt={";
-
- if (has_path)
- {
- s.op->line() << " .pathname=\"" << path << "\",";
- s.op->line() << " .pid=0,";
- }
- else
- {
- s.op->line() << " .pathname=NULL,";
- s.op->line() << " .pid=" << pid << ",";
- }
-
- s.op->line() << " .callback=NULL,";
- s.op->line() << " .vm_callback=&" << vm_callback << ",";
- s.op->line() << " },";
- s.op->line() << " .pp=\"internal\",";
- s.op->line() << " .ph=NULL,";
- s.op->line() << " .flags=(UDPF_NONE),";
- s.op->line() << " .ops={ NULL },";
- s.op->line() << " .events=0,";
- s.op->line() << " .engine_attached=0,";
- s.op->line() << " },";
-}
-
-
-void
utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
@@ -7006,7 +7034,6 @@ 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);
@@ -7214,6 +7241,25 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "return rc;";
s.op->newline(-1) << "}";
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_utrace_vmcbs[] = {";
+ s.op->indent(1);
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
+ }
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ emit_vma_callback_probe_decl (s, "", it->first);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
s.op->newline() << "static struct stap_utrace_probe stap_utrace_probes[] = {";
s.op->indent(1);
@@ -7223,12 +7269,6 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
for (p_b_path_iterator it = probes_by_path.begin();
it != probes_by_path.end(); it++)
{
- // Emit a "fake" probe decl that is really a hook for to get
- // our vm_callback called.
- string path = it->first;
- emit_vm_callback_probe_decl (s, true, path, (int64_t)0,
- "__stp_tf_vm_cb");
-
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
@@ -7243,11 +7283,6 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
for (p_b_pid_iterator it = probes_by_pid.begin();
it != probes_by_pid.end(); it++)
{
- // Emit a "fake" probe decl that is really a hook for to get
- // our vm_callback called.
- emit_vm_callback_probe_decl (s, false, "", it->first,
- "__stp_tf_vm_cb");
-
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
@@ -7266,6 +7301,15 @@ utrace_derived_probe_group::emit_module_init (systemtap_session& s)
return;
s.op->newline();
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "/* ---- utrace vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_utrace_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
s.op->newline() << "/* ---- utrace probes ---- */";
s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
s.op->indent(1);
@@ -7495,7 +7539,6 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "#else";
s.op->newline() << "#include \"uprobes/uprobes.h\"";
s.op->newline() << "#endif";
- s.op->newline() << "#include \"task_finder.c\"";
s.op->newline() << "#ifndef MULTIPLE_UPROBES";
s.op->newline() << "#define MULTIPLE_UPROBES 256"; // maximum possible armed uprobes per process() probe point
@@ -7513,6 +7556,21 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "} stap_uprobes [MAXUPROBES];";
s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_uprobe_vmcbs[] = {";
+ s.op->indent(1);
+ for (unsigned i = 0; i < probes.size(); i++)
+ {
+ uprobe_derived_probe* p = probes[i];
+ if (p->pid != 0)
+ emit_vma_callback_probe_decl (s, "", p->pid);
+ else
+ emit_vma_callback_probe_decl (s, p->module, (int64_t)0);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
s.op->newline() << "static struct stap_uprobe_spec {";
s.op->newline(1) << "struct stap_task_finder_target finder;";
s.op->newline() << "unsigned long address;";
@@ -7713,6 +7771,15 @@ void
uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
if (probes.empty()) return;
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "/* ---- uprobe vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_uprobe_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_uprobe_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
s.op->newline() << "/* ---- user probes ---- */";
s.op->newline() << "for (j=0; j<MAXUPROBES; j++) {";
diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp
index a4beaa12..3043eeed 100644
--- a/testsuite/lib/stap_run.exp
+++ b/testsuite/lib/stap_run.exp
@@ -30,6 +30,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args }
if [file readable $test_file_name] {
lappend cmd $test_file_name
}
+ send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 180
diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp
index 554e88ed..5311be7b 100644
--- a/testsuite/lib/systemtap.exp
+++ b/testsuite/lib/systemtap.exp
@@ -16,6 +16,16 @@ proc use_server_p {} {
}
+proc utrace_p {} {
+ set path "/proc/kallsyms"
+ if {! [catch {exec grep -q utrace_attach $path} dummy]} {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+
proc print_systemtap_version {} {
set version [exec /bin/uname -r]
set location "/boot/vmlinux-$version"
diff --git a/testsuite/systemtap.base/bz5274.exp b/testsuite/systemtap.base/bz5274.exp
index 92441e9e..2f76a43f 100755
--- a/testsuite/systemtap.base/bz5274.exp
+++ b/testsuite/systemtap.base/bz5274.exp
@@ -17,14 +17,7 @@ if {! [installtest_p]} {
return
}
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
catch {exec rm -f $test}
untested "$test -p5"
return
diff --git a/testsuite/systemtap.base/bz6850.exp b/testsuite/systemtap.base/bz6850.exp
index b96ed95c..32ecdaf5 100644
--- a/testsuite/systemtap.base/bz6850.exp
+++ b/testsuite/systemtap.base/bz6850.exp
@@ -3,14 +3,7 @@ set test bz6850
catch {exec gcc -g -o bz6850 $srcdir/$subdir/bz6850.c} err
if {$err == "" && [file exists bz6850]} then { pass "$test compile" } else { fail "$test compile" }
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
catch {exec rm -f $test}
untested "$test -p4"
untested "$test -p5"
diff --git a/testsuite/systemtap.base/itrace.exp b/testsuite/systemtap.base/itrace.exp
index e215bfe7..c7da39c8 100644
--- a/testsuite/systemtap.base/itrace.exp
+++ b/testsuite/systemtap.base/itrace.exp
@@ -2,7 +2,6 @@
# Initialize variables
-set utrace_support_found 0
set exepath "[pwd]/ls_[pid]"
set itrace1_script {
@@ -48,6 +47,26 @@ set itrace2_script {
}
set itrace2_script_output "itraced = 5\r\n"
+set itrace3_script {
+ global branches = 0
+ probe begin
+ {
+ printf("systemtap starting probe\n")
+ }
+ probe process("%s").insn.block
+ {
+ branches += 1
+ if (branches == 5)
+ exit()
+ }
+
+
+ probe end { printf("systemtap ending probe\n")
+ printf("itraced block mode = %%d\n", branches)
+ }
+}
+set itrace3_script_output "itraced block mode = 5\r\n"
+
# Set up our own copy of /bin/ls, to make testing for a particular
# executable easy. We can't use 'ln' here, since we might be creating
@@ -72,14 +91,8 @@ proc run_ls_5_sec {} {
}
-# Try to find utrace_attach symbol in /proc/kallsyms
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-
set TEST_NAME "itrace1"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested $TEST_NAME
@@ -90,7 +103,7 @@ if {$utrace_support_found == 0} {
set TEST_NAME "itrace2"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested $TEST_NAME
@@ -99,5 +112,16 @@ if {$utrace_support_found == 0} {
stap_run $TEST_NAME run_ls_5_sec $itrace2_script_output -e $script
}
+set TEST_NAME "itrace3"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} elseif {![installtest_p]} {
+ untested $TEST_NAME
+} else {
+ send_log "ATTENTION: if arch_has_block_step is not defined for this arch, this testcase will fail\n"
+ set script [format $itrace3_script $exepath]
+ stap_run $TEST_NAME run_ls_5_sec $itrace3_script_output -e $script
+}
+
# Cleanup
exec rm -f $exepath
diff --git a/testsuite/systemtap.base/labels.exp b/testsuite/systemtap.base/labels.exp
index 6db81c54..2f79a502 100644
--- a/testsuite/systemtap.base/labels.exp
+++ b/testsuite/systemtap.base/labels.exp
@@ -1,14 +1,6 @@
set test "labels"
if {![installtest_p]} {untested $test; return}
-
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} { untested "$test"; return }
+if {![utrace_p]} { untested $test; return }
# Compile a C program to use as the user-space probing target
set label_srcpath "[pwd]/labels.c"
diff --git a/testsuite/systemtap.base/static_uprobes.exp b/testsuite/systemtap.base/static_uprobes.exp
index d6b6e1e3..07ff83e9 100644
--- a/testsuite/systemtap.base/static_uprobes.exp
+++ b/testsuite/systemtap.base/static_uprobes.exp
@@ -124,15 +124,7 @@ if { $res != "" } {
}
if {![installtest_p]} {untested $test; return}
-
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$test"
catch {exec rm -f $sup_srcpath}
return
diff --git a/testsuite/systemtap.base/uprobes.exp b/testsuite/systemtap.base/uprobes.exp
index 89250e7b..6344cbf0 100644
--- a/testsuite/systemtap.base/uprobes.exp
+++ b/testsuite/systemtap.base/uprobes.exp
@@ -18,14 +18,7 @@ if [file exists $path] then { pass "$test prep" } else { fail "$test prep" }
catch {exec gcc -g -o jennie jennie.c} err
if {$err == "" && [file exists jennie]} then { pass "$test compile" } else { fail "$test compile" }
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$test -p4"; untested "$test -p5"
catch {exec rm -f jennie.c jennie}
return
diff --git a/testsuite/systemtap.base/uprobes_lib.exp b/testsuite/systemtap.base/uprobes_lib.exp
index ae1b72e8..63ef957a 100644
--- a/testsuite/systemtap.base/uprobes_lib.exp
+++ b/testsuite/systemtap.base/uprobes_lib.exp
@@ -10,21 +10,23 @@ set testflags "additional_flags=-g additional_flags=-O"
set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared"
set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
-# Only run on make installcheck
-if {! [installtest_p]} { untested "$test"; return }
-
# Compile our test program and library.
set res [target_compile $testsrclib $testso executable $testlibflags]
if { $res != "" } {
verbose "target_compile for $testso failed: $res" 2
- fail "unable to compile $testsrclib"
+ fail "$test compile $testsrclib"
return
+} else {
+ pass "$test compile $testsrclib"
}
+
set res [target_compile $testsrc $testexe executable $maintestflags]
if { $res != "" } {
verbose "target_compile failed: $res" 2
- fail "unable to compile $testsrc"
+ fail "$test compile $testsrc"
return
+} else {
+ pass "$test compile $testsrc"
}
# XXX main_func needs another/extra test. Disabled for now.
@@ -33,6 +35,9 @@ if { $res != "" } {
# lib_func}
set ::result_string {lib_func}
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested $test; return }
stap_run2 $srcdir/$subdir/$test.stp -c $testexe
#exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp
index 1467d9c8..8d323a8a 100644
--- a/testsuite/systemtap.base/utrace_p4.exp
+++ b/testsuite/systemtap.base/utrace_p4.exp
@@ -7,8 +7,6 @@
# utrace doesn't exist in the kernel, marks the tests as 'untested'.
# Initialize variables
-set utrace_support_found 0
-
set begin_script {"probe process(\"/bin/ls\").begin { print(\"ls begin\") }"}
set end_script {"probe process(\"/bin/ls\").end { print(\"ls end\") }"}
set syscall_script {"probe process(\"/bin/ls\").syscall { printf(\"|%d\", \$syscall) }"}
@@ -24,18 +22,12 @@ set pid_syscall_return_script {"probe process(123).syscall.return { printf(\"|%d
set pid_thread_begin_script {"probe process(123).thread.begin { print(\"123 thread.begin\") }"}
set pid_thread_end_script {"probe process(123).thread.end { print(\"123 thread.end\") }"}
-# Try to find utrace_attach symbol in /proc/kallsyms
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-
#
# Do some utrace compile tests.
#
set TEST_NAME "UTRACE_P4_01"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a begin script using a path
@@ -43,7 +35,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_01_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a begin script using a pid
@@ -51,7 +43,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_02"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a end script using a path
@@ -59,7 +51,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_02_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a end script using a pid
@@ -67,7 +59,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_03"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall script using a path
@@ -75,7 +67,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_03_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall script using a pid
@@ -83,7 +75,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_04"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall return script using a path
@@ -91,7 +83,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_04_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall return script using a pid
@@ -99,7 +91,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_05"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.begin script using a path
@@ -107,7 +99,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_05_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.begin script using a pid
@@ -115,7 +107,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_06"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.end script using a path
@@ -123,7 +115,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_06_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.end script using a pid
@@ -131,7 +123,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_07"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an system-wide begin script
diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp
index 33281350..3d432dc3 100644
--- a/testsuite/systemtap.base/utrace_p5.exp
+++ b/testsuite/systemtap.base/utrace_p5.exp
@@ -1,7 +1,6 @@
# Utrace run (pass 5) tests.
# Initialize variables
-set utrace_support_found 0
set exepath "[pwd]/cat_[pid]"
set multi_srcpath "$srcdir/systemtap.base/utrace_p5_multi.c"
set multi_exepath "[pwd]/utrace_p5_multi_[pid]"
@@ -90,12 +89,6 @@ set bz6841_script {
}
set bz6841_script_output ".+ issues syscall \\d+ times\r\n"
-# Try to find utrace_attach symbol in /proc/kallsyms
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-
# Set up our own copy of /bin/cat, to make testing for a particular
# executable easy. We can't use 'ln' here, since we might be creating
# a cross-device link. We can't use 'ln -s' here, since the kernel
@@ -138,7 +131,7 @@ proc run_utrace_p5_multi {} {
}
set TEST_NAME "UTRACE_P5_01"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -148,7 +141,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_02"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -158,7 +151,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_03"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -168,7 +161,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_04"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -178,7 +171,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_05"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -189,7 +182,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_06"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -200,7 +193,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_07"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
diff --git a/testsuite/systemtap.context/usymbols.c b/testsuite/systemtap.context/usymbols.c
new file mode 100644
index 00000000..7c590724
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.c
@@ -0,0 +1,39 @@
+/* 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 from the main executable,
+ * and then the library through calling signal.
+ *
+ * FIXME. We call into the library to get the right symbol. If we
+ * register the handler from the main executable. We 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);
+
+// function from our library
+int lib_main (void);
+
+void
+main_handler (int signum)
+{
+ /* dummy handler, just used for the address... */
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ // Use SIGFPE since we never expect that to be triggered.
+ signal(SIGFPE, main_handler);
+ lib_main();
+}
diff --git a/testsuite/systemtap.context/usymbols.exp b/testsuite/systemtap.context/usymbols.exp
new file mode 100644
index 00000000..f95fd896
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.exp
@@ -0,0 +1,82 @@
+set test "./usymbols"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/usymbols.c"
+set testsrclib "$testpath/usymbols_lib.c"
+set testexe "[pwd]/usymbols"
+set testlibname "usymbols"
+set testlibdir "[pwd]"
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test -p5"; return }
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "unable to compile $testsrclib"
+ return
+}
+set res [target_compile $testsrc $testexe executable $maintestflags]
+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 or the library).
+set testscript {
+ probe syscall.rt_sigaction {
+ if (pid() == target() && execname() == "%s") {
+ handler = $act->sa_handler;
+ printf("handler: %%s\n", symbolname(handler));
+ }
+ }
+ /* track through uprobes, so as to make sure we have the symbols */
+ probe process("%s").function("*") { printf(""); }
+}
+
+set output {handler: main_handler
+handler: lib_handler}
+
+# 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 $testlibname]} libpath
+set libpath [lindex [split $libpath " "] 2]
+send_log "libpath: $libpath\n"
+if {[string equal "link" [file type $libpath]]} {
+ set libpath [file join [file dirname $libpath] [file readlink $libpath]]
+}
+send_log "libpath: $libpath\n"
+
+# XXX Cheat, explicitly add STP_NEED_VMA_TRACKER
+set cmd [concat stap -DSTP_NEED_VMA_TRACKER -d $libpath -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 $testso
diff --git a/testsuite/systemtap.context/usymbols_lib.c b/testsuite/systemtap.context/usymbols_lib.c
new file mode 100644
index 00000000..faccb39b
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols_lib.c
@@ -0,0 +1,29 @@
+/* usymbol test case - library helper
+ * 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 set through signal
+ * from this library.
+ */
+
+#include <signal.h>
+typedef void (*sighandler_t)(int);
+
+void
+lib_handler (int signum)
+{
+ /* dummy handler, just used for the address... */
+}
+
+void
+lib_main ()
+{
+ // Use SIGFPE since we never expect that to be triggered.
+ signal(SIGFPE, lib_handler);
+}
diff --git a/testsuite/systemtap.pass1-4/buildok.exp b/testsuite/systemtap.pass1-4/buildok.exp
index 08d50fb5..3731fc06 100644
--- a/testsuite/systemtap.pass1-4/buildok.exp
+++ b/testsuite/systemtap.pass1-4/buildok.exp
@@ -12,6 +12,7 @@ foreach file [lsort [glob -nocomplain $srcdir/$self/*.stp]] {
buildok/process_test.stp {setup_kfail 1155 *-*-*}
buildok/rpc-all-probes.stp {setup_kfail 4413 *-*-*}
buildok/nfs-all-probes.stp {setup_kfail 4413 *-*-*}
+ buildok/per-process-syscall.stp {if {![utrace_p]} { setup_kfail 9999 *-*-*} }
}
if {$rc == 0} { pass $test } else { fail $test }
}
diff --git a/util.cxx b/util.cxx
index 68cc27f7..5fa7a5f2 100644
--- a/util.cxx
+++ b/util.cxx
@@ -20,13 +20,15 @@
#include <cerrno>
extern "C" {
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <fcntl.h>
#include <pwd.h>
-#include <unistd.h>
+#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
}
using namespace std;
@@ -275,4 +277,35 @@ git_revision(const string& path)
return revision;
}
+
+static pid_t spawned_pid = 0;
+
+// Runs a command with a saved PID, so we can kill it from the signal handler
+int
+stap_system(const char *command)
+{
+ const char * argv[] = { "sh", "-c", command, NULL };
+ int ret, status;
+
+ spawned_pid = 0;
+ ret = posix_spawn(&spawned_pid, "/bin/sh", NULL, NULL,
+ const_cast<char **>(argv), environ);
+ if (ret == 0)
+ {
+ if (waitpid(spawned_pid, &status, 0) == spawned_pid)
+ ret = WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
+ else
+ ret = errno;
+ }
+ spawned_pid = 0;
+ return ret;
+}
+
+// Send a signal to our spawned command
+int
+kill_stap_spawn(int sig)
+{
+ return spawned_pid ? kill(spawned_pid, sig) : 0;
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/util.h b/util.h
index d385be02..7c557049 100644
--- a/util.h
+++ b/util.h
@@ -13,6 +13,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens,
std::string find_executable(const std::string& name);
const std::string cmdstr_quoted(const std::string& cmd);
std::string git_revision(const std::string& path);
+int stap_system(const char *command);
+int kill_stap_spawn(int sig);
// stringification generics