summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in4
-rw-r--r--runtime/staprun/ChangeLog15
-rw-r--r--runtime/staprun/cap.c4
-rw-r--r--runtime/staprun/ctl.c13
-rw-r--r--runtime/staprun/mainloop.c2
-rw-r--r--runtime/staprun/staprun.c5
-rw-r--r--runtime/staprun/staprun.h10
-rw-r--r--runtime/staprun/staprun_funcs.c46
-rw-r--r--runtime/staprun/symbols.c13
-rw-r--r--runtime/transport/ChangeLog10
-rw-r--r--runtime/transport/control.c252
-rw-r--r--runtime/transport/procfs.c299
-rw-r--r--runtime/transport/transport.c15
-rw-r--r--tapsets.cxx330
-rw-r--r--testsuite/systemtap.syscall/ChangeLog3
-rw-r--r--testsuite/systemtap.syscall/timer.c2
18 files changed, 821 insertions, 220 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b68930a..ff71d731 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2007-10-12 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (dwflpp::setup): Added 'debuginfo_needed' parameter
+ to not error if no debuginfo present.
+ (hex_dump): New function.
+ (mark_query::handle_query_module): Updated for
+ 10/2/2007 markers patch. Currently only handles markers in the
+ kernel image itself - not in modules.
+
+2007-10-12 Martin Hunt <hunt@redhat.com>
+
+ * Makefile.am (staprun_LDADD): Add -lpthread.
+ * Makefile.in: Rebuilt.
+
2007-10-11 Frank Ch. Eigler <fche@elastic.org>
* systemtap.spec.in: Make -testsuite subrpm require dejagnu.
diff --git a/Makefile.am b/Makefile.am
index 7e28591c..2da4da73 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,9 +55,9 @@ staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
runtime/staprun/ctl.c runtime/staprun/common.c \
runtime/staprun/cap.c runtime/staprun/symbols.c
-staprun_CPPFLAGS = $(AM_CPPFLAGS) -DSINGLE_THREADED
+staprun_CPPFLAGS = $(AM_CPPFLAGS)
staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-staprun_LDADD = @PROCFLAGS@ @cap_LIBS@
+staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread
stapio_SOURCES = runtime/staprun/stapio.c \
runtime/staprun/mainloop.c runtime/staprun/common.c \
diff --git a/Makefile.in b/Makefile.in
index 193e021a..77e5be8d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -283,9 +283,9 @@ staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
runtime/staprun/ctl.c runtime/staprun/common.c \
runtime/staprun/cap.c runtime/staprun/symbols.c
-staprun_CPPFLAGS = $(AM_CPPFLAGS) -DSINGLE_THREADED
+staprun_CPPFLAGS = $(AM_CPPFLAGS)
staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-staprun_LDADD = @PROCFLAGS@ @cap_LIBS@
+staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread
stapio_SOURCES = runtime/staprun/stapio.c \
runtime/staprun/mainloop.c runtime/staprun/common.c \
runtime/staprun/ctl.c \
diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog
index 2a9029d0..f03f3606 100644
--- a/runtime/staprun/ChangeLog
+++ b/runtime/staprun/ChangeLog
@@ -1,3 +1,18 @@
+2007-10-12 Martin Hunt <hunt@redhat.com>
+ Changes to separate the symbols from the command channel.
+
+ * cap.c (init_cap): Add CAP_DAC_OVERRIDE.
+ * staprun.h: Change init_ctl_channel prototype.
+ * ctl.c (init_ctl_channel): Modify to open either
+ a command or symbol channel. Use ".cmd" and ".symbols"
+ as the new names.
+ * mainloop.c (init_stapio): Call init_ctl_channel(0);
+ * staprun.c (cleanup): Call stop_symbol_thread().
+ (main): Call start_symbol_thread().
+ * staprun_funcs.c (handle_symbols): Make a thread.
+ (start_symbol_thread): New.
+ (stop_symbol_thread): New.
+
2007-10-11 Frank Ch. Eigler <fche@elastic.org>
* staprun.c (main): Move checks for init_cap and getuid
diff --git a/runtime/staprun/cap.c b/runtime/staprun/cap.c
index df4a7130..6f22dfc9 100644
--- a/runtime/staprun/cap.c
+++ b/runtime/staprun/cap.c
@@ -28,7 +28,7 @@
_perr(msg); \
exit(1); \
} \
-
+
/*
* init_cap() sets up the initial capabilities for staprun. Then
* it calls prctl( PR_SET_KEEPCAPS) to arrrange to keep these capabilities
@@ -57,7 +57,7 @@
int init_cap(void)
{
cap_t caps = cap_init();
- cap_value_t capv[] = {CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID};
+ cap_value_t capv[] = {CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE};
const int numcaps = sizeof(capv) / sizeof(capv[0]);
uid_t uid = getuid();
gid_t gid = getgid();
diff --git a/runtime/staprun/ctl.c b/runtime/staprun/ctl.c
index 7fe57206..af7e6c1a 100644
--- a/runtime/staprun/ctl.c
+++ b/runtime/staprun/ctl.c
@@ -12,18 +12,23 @@
#include "staprun.h"
-int init_ctl_channel(void)
+int init_ctl_channel(int symbols)
{
- char buf[PATH_MAX];
+ char *cname, buf[PATH_MAX];
struct statfs st;
int old_transport = 0;
+
+ if (symbols)
+ cname = ".symbols";
+ else
+ cname = ".cmd";
if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) {
- if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/cmd", modname))
+ if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/%s", modname, cname))
return -1;
} else {
old_transport = 1;
- if (sprintf_chk(buf, "/proc/systemtap/%s/cmd", modname))
+ if (sprintf_chk(buf, "/proc/systemtap/%s/%s", modname, cname))
return -1;
}
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index d919164f..c0722b56 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -164,7 +164,7 @@ int init_stapio(void)
dbug(2, "init_stapio\n");
/* create control channel */
- use_old_transport = init_ctl_channel();
+ use_old_transport = init_ctl_channel(0);
if (use_old_transport < 0) {
err("Failed to initialize control channel.\n");
return -1;
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index 44ac0313..f4e67fdb 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -181,6 +181,8 @@ static void cleanup(int rc)
if (setpriority (PRIO_PROCESS, 0, 0) < 0)
_perr("setpriority");
+ stop_symbol_thread();
+
/* rc == 2 means disconnected */
if (rc == 2)
return;
@@ -276,8 +278,7 @@ int main(int argc, char **argv)
exit(1);
setup_staprun_signals();
- if (!attach_mod)
- handle_symbols();
+ start_symbol_thread();
rc = run_stapio(argv);
cleanup(rc);
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 685de294..c22cc4f3 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -35,12 +35,7 @@
#include <linux/version.h>
#include <sys/capability.h>
-#define DEBUG
-#ifdef DEBUG
#define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}}
-#else
-#define dbug(level, args...) ;
-#endif /* DEBUG */
extern char *__name__;
@@ -125,7 +120,7 @@ int send_request(int type, void *data, int len);
void cleanup_and_exit (int);
int do_module(void *);
void do_kernel_symbols(void);
-int init_ctl_channel(void);
+int init_ctl_channel(int);
void close_ctl_channel(void);
int init_relayfs(void);
void close_relayfs(void);
@@ -145,7 +140,8 @@ int insert_module(const char *path, const char *special_options,
char **options);
int mountfs(void);
int check_permissions(void);
-void handle_symbols(void);
+void start_symbol_thread(void);
+void stop_symbol_thread(void);
/* common.c functions */
void parse_args(int argc, char **argv);
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
index eec4ae63..86a72985 100644
--- a/runtime/staprun/staprun_funcs.c
+++ b/runtime/staprun/staprun_funcs.c
@@ -385,8 +385,10 @@ int check_permissions(void)
return check_path();
}
-/* wait for symbol requests and reply */
-void handle_symbols(void)
+pthread_t symbol_thread_id = (pthread_t)0;
+
+/* Symbol handling thread */
+void *handle_symbols(void __attribute__((unused)) *arg)
{
ssize_t nb;
void *data;
@@ -395,12 +397,6 @@ void handle_symbols(void)
dbug(2, "waiting for symbol requests\n");
- /* create control channel */
- if (init_ctl_channel() < 0) {
- err("Failed to initialize control channel.\n");
- exit(1);
- }
-
while (1) { /* handle messages from control channel */
nb = read(control_channel, recvbuf, sizeof(recvbuf));
if (nb <= 0) {
@@ -417,7 +413,7 @@ void handle_symbols(void)
{
dbug(2, "STP_MODULES request received\n");
do_module(data);
- goto done;
+ break;
}
case STP_SYMBOLS:
{
@@ -439,6 +435,36 @@ void handle_symbols(void)
err("WARNING: ignored message of type %d\n", (type));
}
}
-done:
+
+ return NULL;
+}
+
+void start_symbol_thread(void)
+{
+ int status;
+
+ /* create symbol control channel */
+ status = do_cap(CAP_DAC_OVERRIDE, init_ctl_channel, 1);
+ drop_cap(CAP_DAC_OVERRIDE);
+ if (status < 0) {
+ err("Failed to initialize control channel.\n");
+ exit(1);
+ }
+ status = pthread_create(&symbol_thread_id, NULL, handle_symbols, NULL);
+ if (status) {
+ perr("Failed to create symbol thread.\n");
+ exit(1);
+ }
+}
+
+void stop_symbol_thread(void)
+{
+
+ if (symbol_thread_id) {
+ dbug(2, "Stopping symbol thread.\n");
+ pthread_cancel(symbol_thread_id);
+ pthread_join(symbol_thread_id, NULL);
+ }
close_ctl_channel();
}
+
diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c
index 61b56b2e..315362fa 100644
--- a/runtime/staprun/symbols.c
+++ b/runtime/staprun/symbols.c
@@ -140,7 +140,10 @@ err0:
}
#undef SECDIR
-void send_module (char *mname)
+/*
+ * For modules, we send the name, section names, and offsets
+ */
+static void send_module (char *mname)
{
char data[32768];
int len = get_sections(mname, data, sizeof(data));
@@ -152,6 +155,9 @@ void send_module (char *mname)
}
}
+/*
+ * Send either all modules, or a specific one.
+ */
int do_module (void *data)
{
struct _stp_module *mod = (struct _stp_module *)data;
@@ -183,6 +189,11 @@ static int compar(const void *p1, const void *p2)
#define MAX_SYMBOLS 32*1024
+/*
+ * Read /proc/kallsyms and send all kernel symbols to the
+ * systemtap module. Ignore module symbols; the systemtap module
+ * can access them directly.
+ */
void do_kernel_symbols(void)
{
FILE *kallsyms=NULL;
diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog
index e36f89d5..66811376 100644
--- a/runtime/transport/ChangeLog
+++ b/runtime/transport/ChangeLog
@@ -1,3 +1,13 @@
+2007-10-12 Martin Hunt <hunt@redhat.com>
+
+ * transport.c (_stp_ask_for_symbols): Don't ask for
+ transport_info yet. Need to wait until symbols are
+ received.
+ (_stp_work_queue): Rename _stp_ready_q to _stp_ctl_ready_q.
+ * procfs.c: Create a ".symbols" channel and use it for
+ STP_MODULE and STP_SYMBOLS. Rename "cmd" channel to ".cmd".
+ * control.c: Ditto.
+
2007-09-21 Martin Hunt <hunt@redhat.com>
From Alan Brunelle
* control.c (_stp_ctl_read_cmd): Cast count to an int before printing.
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
index 42f23063..ae731659 100644
--- a/runtime/transport/control.c
+++ b/runtime/transport/control.c
@@ -12,16 +12,17 @@
#define STP_DEFAULT_BUFFERS 50
static int _stp_current_buffers = STP_DEFAULT_BUFFERS;
-static struct list_head _stp_ready_q;
+static struct list_head _stp_ctl_ready_q;
+static struct list_head _stp_sym_ready_q;
static struct list_head _stp_pool_q;
spinlock_t _stp_pool_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t _stp_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_ctl_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_sym_ready_lock = SPIN_LOCK_UNLOCKED;
-static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int type;
- static int started = 0, initialized = 0;
if (count < sizeof(int))
return 0;
@@ -29,7 +30,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
if (get_user(type, (int __user *)buf))
return -EFAULT;
- // kbug ("count:%d type:%d\n", count, type);
+ kbug ("count:%d type:%d\n", count, type);
if (type == STP_SYMBOLS) {
count -= sizeof(long);
@@ -40,8 +41,45 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
}
switch (type) {
+ case STP_SYMBOLS:
+
+ if (count)
+ count = _stp_do_symbols(buf, count);
+ break;
+ case STP_MODULE:
+ if (count)
+ count = _stp_do_module(buf, count);
+ else {
+ /* count == 0 indicates end of initial modules list */
+ _stp_ctl_send(STP_TRANSPORT, NULL, 0);
+ }
+ break;
+ default:
+ errk ("invalid symbol command type %d\n", type);
+ return -EINVAL;
+ }
+
+ return count;
+}
+static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int type;
+ static int started = 0;
+
+ if (count < sizeof(int))
+ return 0;
+
+ if (get_user(type, (int __user *)buf))
+ return -EFAULT;
+
+ // kbug ("count:%d type:%d\n", count, type);
+
+ count -= sizeof(int);
+ buf += sizeof(int);
+
+ switch (type) {
case STP_START:
- {
if (started == 0) {
struct _stp_msg_start st;
if (count < sizeof(st))
@@ -52,20 +90,6 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
started = 1;
}
break;
- }
-
- case STP_SYMBOLS:
- if (initialized == 0 && count && current->pid == _stp_init_pid)
- count = _stp_do_symbols(buf, count);
- break;
- case STP_MODULE:
- if (initialized == 0 && current->pid == _stp_init_pid) {
- if (count)
- count = _stp_do_module(buf, count);
- else
- initialized = 1;
- }
- break;
case STP_EXIT:
_stp_exit_flag = 1;
break;
@@ -93,6 +117,7 @@ struct _stp_buffer {
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
+static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq);
#ifdef DEBUG
static void _stp_ctl_write_dbug (int type, void *data, int len)
@@ -113,12 +138,6 @@ static void _stp_ctl_write_dbug (int type, void *data, int len)
snprintf(buf, sizeof(buf), "%s", (char *)data);
printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf);
break;
- case STP_SYMBOLS:
- printk("_stp_ctl_write: sending STP_SYMBOLS\n");
- break;
- case STP_MODULE:
- printk("_stp_ctl_write: sending STP_MODULE\n");
- break;
case STP_TRANSPORT:
printk("_stp_ctl_write: sending STP_TRANSPORT\n");
break;
@@ -127,6 +146,20 @@ static void _stp_ctl_write_dbug (int type, void *data, int len)
break;
}
}
+static void _stp_sym_write_dbug (int type, void *data, int len)
+{
+ switch (type) {
+ case STP_SYMBOLS:
+ printk("_stp_sym_write: sending STP_SYMBOLS\n");
+ break;
+ case STP_MODULE:
+ printk("_stp_sym_write: sending STP_MODULE\n");
+ break;
+ default:
+ printk("_stp_sym_write: ERROR: unknown message type: %d\n", type);
+ break;
+ }
+}
#endif
static int _stp_ctl_write (int type, void *data, unsigned len)
@@ -134,7 +167,6 @@ static int _stp_ctl_write (int type, void *data, unsigned len)
struct _stp_buffer *bptr;
unsigned long flags;
unsigned numtrylock;
-
#ifdef DEBUG
_stp_ctl_write_dbug(type, data, len);
#endif
@@ -166,13 +198,54 @@ static int _stp_ctl_write (int type, void *data, unsigned len)
/* put it on the pool of ready buffers */
numtrylock = 0;
- while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
+ while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
+
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- list_add_tail(&bptr->list, &_stp_ready_q);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ list_add_tail(&bptr->list, &_stp_ctl_ready_q);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
+
+ return len;
+}
+
+static int _stp_sym_write (int type, void *data, unsigned len)
+{
+ struct _stp_buffer *bptr;
+ unsigned long flags;
+
+#ifdef DEBUG
+ _stp_sym_write_dbug(type, data, len);
+#endif
+
+ /* make sure we won't overflow the buffer */
+ if (unlikely(len > STP_CTL_BUFFER_SIZE))
+ return 0;
+
+ spin_lock_irqsave (&_stp_pool_lock, flags);
+ if (unlikely(list_empty(&_stp_pool_q))) {
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+ dbug("_stp_pool_q empty\n");
+ return -1;
+ }
+
+ /* get the next buffer from the pool */
+ bptr = (struct _stp_buffer *)_stp_pool_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ bptr->type = type;
+ memcpy(bptr->buf, data, len);
+ bptr->len = len;
+
+ /* put it on the pool of ready buffers */
+ spin_lock_irqsave (&_stp_sym_ready_lock, flags);
+ list_add_tail(&bptr->list, &_stp_sym_ready_q);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* OK, it's queued. Now signal any waiters. */
+ wake_up_interruptible(&_stp_sym_wq);
return len;
}
@@ -182,13 +255,60 @@ static int _stp_ctl_send (int type, void *data, int len)
{
int err, trylimit = 50;
kbug("ctl_send: type=%d len=%d\n", type, len);
- while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
- msleep (5);
+ if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) {
+ while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ } else {
+ while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ }
kbug("returning %d\n", err);
return err;
}
static ssize_t
+_stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct _stp_buffer *bptr;
+ int len;
+ unsigned long flags;
+
+ /* wait for nonempty ready queue */
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ while (list_empty(&_stp_sym_ready_q)) {
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ if (wait_event_interruptible(_stp_sym_wq, !list_empty(&_stp_sym_ready_q)))
+ return -ERESTARTSYS;
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ }
+
+ /* get the next buffer off the ready list */
+ bptr = (struct _stp_buffer *)_stp_sym_ready_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* write it out */
+ len = bptr->len + 4;
+ if (len > count || copy_to_user(buf, &bptr->type, len)) {
+ /* now what? We took it off the queue then failed to send it */
+ /* we can't put it back on the queue because it will likely be out-of-order */
+ /* fortunately this should never happen */
+ /* FIXME need to mark this as a transport failure */
+ errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
+ return -EFAULT;
+ }
+
+ /* put it on the pool of free buffers */
+ spin_lock_irqsave(&_stp_pool_lock, flags);
+ list_add_tail(&bptr->list, &_stp_pool_q);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ return len;
+}
+
+static ssize_t
_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct _stp_buffer *bptr;
@@ -196,20 +316,20 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
unsigned long flags;
/* wait for nonempty ready queue */
- spin_lock_irqsave(&_stp_ready_lock, flags);
- while (list_empty(&_stp_ready_q)) {
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
+ while (list_empty(&_stp_ctl_ready_q)) {
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ready_q)))
+ if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ctl_ready_q)))
return -ERESTARTSYS;
- spin_lock_irqsave(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
}
/* get the next buffer off the ready list */
- bptr = (struct _stp_buffer *)_stp_ready_q.next;
+ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.next;
list_del_init(&bptr->list);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
/* write it out */
len = bptr->len + 4;
@@ -230,9 +350,28 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
return len;
}
+static int _stp_sym_opens = 0;
+static int _stp_sym_open_cmd (struct inode *inode, struct file *file)
+{
+ /* only allow one reader */
+ if (_stp_sym_opens)
+ return -1;
+
+ _stp_sym_opens++;
+ return 0;
+}
+
+static int _stp_sym_close_cmd (struct inode *inode, struct file *file)
+{
+ if (_stp_sym_opens)
+ _stp_sym_opens--;
+ return 0;
+}
+
static int _stp_ctl_opens = 0;
static int _stp_ctl_open_cmd (struct inode *inode, struct file *file)
{
+ /* only allow one reader */
if (_stp_ctl_opens)
return -1;
@@ -260,20 +399,30 @@ static struct file_operations _stp_ctl_fops_cmd = {
.release = _stp_ctl_close_cmd,
};
+static struct file_operations _stp_sym_fops_cmd = {
+ .owner = THIS_MODULE,
+ .read = _stp_sym_read_cmd,
+ .write = _stp_sym_write_cmd,
+ .open = _stp_sym_open_cmd,
+ .release = _stp_sym_close_cmd,
+};
+
static struct dentry *_stp_cmd_file = NULL;
+static struct dentry *_stp_sym_file = NULL;
static int _stp_register_ctl_channel (void)
{
int i;
struct list_head *p, *tmp;
char buf[32];
-
+
if (_stp_utt == NULL) {
errk("_expected _stp_utt to be set.\n");
return -1;
}
- INIT_LIST_HEAD(&_stp_ready_q);
+ INIT_LIST_HEAD(&_stp_ctl_ready_q);
+ INIT_LIST_HEAD(&_stp_sym_ready_q);
INIT_LIST_HEAD(&_stp_pool_q);
/* allocate buffers */
@@ -285,17 +434,23 @@ static int _stp_register_ctl_channel (void)
_stp_allocated_net_memory += sizeof(struct _stp_buffer);
list_add (p, &_stp_pool_q);
}
-
- /* create [debugfs]/systemtap/module_name/cmd */
- _stp_cmd_file = debugfs_create_file("cmd", 0600, _stp_utt->dir, NULL, &_stp_ctl_fops_cmd);
+ /* create [debugfs]/systemtap/module_name/.cmd */
+ _stp_cmd_file = debugfs_create_file(".cmd", 0600, _stp_utt->dir, NULL, &_stp_ctl_fops_cmd);
if (_stp_cmd_file == NULL)
goto err0;
- _stp_cmd_file->d_inode->i_uid = _stp_uid;;
+ _stp_cmd_file->d_inode->i_uid = _stp_uid;
_stp_cmd_file->d_inode->i_gid = _stp_gid;
+
+ /* create [debugfs]/systemtap/module_name/.symbols */
+ _stp_sym_file = debugfs_create_file(".symbols", 0600, _stp_utt->dir, NULL, &_stp_sym_fops_cmd);
+ if (_stp_sym_file == NULL)
+ goto err0;
return 0;
err0:
+ if (_stp_cmd_file) debugfs_remove(_stp_cmd_file);
+
list_for_each_safe(p, tmp, &_stp_pool_q) {
list_del(p);
kfree(p);
@@ -308,6 +463,7 @@ err0:
static void _stp_unregister_ctl_channel (void)
{
struct list_head *p, *tmp;
+ if (_stp_sym_file) debugfs_remove(_stp_sym_file);
if (_stp_cmd_file) debugfs_remove(_stp_cmd_file);
/* free memory pools */
@@ -315,7 +471,11 @@ static void _stp_unregister_ctl_channel (void)
list_del(p);
kfree(p);
}
- list_for_each_safe(p, tmp, &_stp_ready_q) {
+ list_for_each_safe(p, tmp, &_stp_sym_ready_q) {
+ list_del(p);
+ kfree(p);
+ }
+ list_for_each_safe(p, tmp, &_stp_ctl_ready_q) {
list_del(p);
kfree(p);
}
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
index be672825..88740847 100644
--- a/runtime/transport/procfs.c
+++ b/runtime/transport/procfs.c
@@ -12,10 +12,12 @@
#define STP_DEFAULT_BUFFERS 256
static int _stp_current_buffers = STP_DEFAULT_BUFFERS;
-static struct list_head _stp_ready_q;
+static struct list_head _stp_ctl_ready_q;
+static struct list_head _stp_sym_ready_q;
static struct list_head _stp_pool_q;
spinlock_t _stp_pool_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t _stp_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_ctl_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_sym_ready_lock = SPIN_LOCK_UNLOCKED;
#ifdef STP_BULKMODE
extern int _stp_relay_flushing;
@@ -63,11 +65,10 @@ static struct file_operations _stp_proc_fops = {
};
#endif /* STP_BULKMODE */
-static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int type;
- static int started = 0, initialized = 0;
if (count < sizeof(int))
return 0;
@@ -75,7 +76,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
if (get_user(type, (int __user *)buf))
return -EFAULT;
- //printk ("_stp_proc_write_cmd. count:%d type:%d\n", count, type);
+ kbug ("count:%d type:%d\n", (int)count, type);
if (type == STP_SYMBOLS) {
count -= sizeof(long);
@@ -86,8 +87,45 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
}
switch (type) {
+ case STP_SYMBOLS:
+
+ if (count)
+ count = _stp_do_symbols(buf, count);
+ break;
+ case STP_MODULE:
+ if (count)
+ count = _stp_do_module(buf, count);
+ else {
+ /* count == 0 indicates end of initial modules list */
+ _stp_ctl_send(STP_TRANSPORT, NULL, 0);
+ }
+ break;
+ default:
+ errk ("invalid symbol command type %d\n", type);
+ return -EINVAL;
+ }
+
+ return count;
+}
+static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int type;
+ static int started = 0;
+
+ if (count < sizeof(int))
+ return 0;
+
+ if (get_user(type, (int __user *)buf))
+ return -EFAULT;
+
+ // kbug ("count:%d type:%d\n", count, type);
+
+ count -= sizeof(int);
+ buf += sizeof(int);
+
+ switch (type) {
case STP_START:
- {
if (started == 0) {
struct _stp_msg_start st;
if (count < sizeof(st))
@@ -98,20 +136,6 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
started = 1;
}
break;
- }
-
- case STP_SYMBOLS:
- if (initialized == 0 && count && current->pid == _stp_init_pid)
- count = _stp_do_symbols(buf, count);
- break;
- case STP_MODULE:
- if (initialized == 0 && current->pid == _stp_init_pid) {
- if (count)
- count = _stp_do_module(buf, count);
- else
- initialized = 1;
- }
- break;
case STP_EXIT:
_stp_exit_flag = 1;
break;
@@ -131,6 +155,52 @@ struct _stp_buffer {
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
+static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq);
+
+#ifdef DEBUG
+static void _stp_ctl_write_dbug (int type, void *data, int len)
+{
+ char buf[64];
+ switch (type) {
+ case STP_REALTIME_DATA:
+ break;
+ case STP_START:
+ printk("_stp_ctl_write: sending STP_START\n");
+ break;
+ case STP_EXIT:
+ printk("_stp_ctl_write: sending STP_EXIT\n");
+ break;
+ case STP_OOB_DATA:
+ snprintf(buf, sizeof(buf), "%s", (char *)data);
+ printk("_stp_ctl_write: sending %d bytes of STP_OOB_DATA: %s\n", len, buf);
+ break;
+ case STP_SYSTEM:
+ snprintf(buf, sizeof(buf), "%s", (char *)data);
+ printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf);
+ break;
+ case STP_TRANSPORT:
+ printk("_stp_ctl_write: sending STP_TRANSPORT\n");
+ break;
+ default:
+ printk("_stp_ctl_write: ERROR: unknown message type: %d\n", type);
+ break;
+ }
+}
+static void _stp_sym_write_dbug (int type, void *data, int len)
+{
+ switch (type) {
+ case STP_SYMBOLS:
+ printk("_stp_sym_write: sending STP_SYMBOLS\n");
+ break;
+ case STP_MODULE:
+ printk("_stp_sym_write: sending STP_MODULE\n");
+ break;
+ default:
+ printk("_stp_sym_write: ERROR: unknown message type: %d\n", type);
+ break;
+ }
+}
+#endif
static int _stp_ctl_write (int type, void *data, int len)
{
@@ -138,27 +208,31 @@ static int _stp_ctl_write (int type, void *data, int len)
unsigned long flags;
unsigned numtrylock;
+#ifdef DEBUG
+ _stp_ctl_write_dbug(type, data, len);
+#endif
+
#define WRITE_AGG
#ifdef WRITE_AGG
numtrylock = 0;
- while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
+ while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- if (!list_empty(&_stp_ready_q)) {
- bptr = (struct _stp_buffer *)_stp_ready_q.prev;
+ if (!list_empty(&_stp_ctl_ready_q)) {
+ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.prev;
if (bptr->len + len <= STP_BUFFER_SIZE
&& type == STP_REALTIME_DATA
&& bptr->type == STP_REALTIME_DATA) {
memcpy (bptr->buf + bptr->len, data, len);
bptr->len += len;
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
return len;
}
}
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
#endif
/* make sure we won't overflow the buffer */
@@ -171,8 +245,9 @@ static int _stp_ctl_write (int type, void *data, int len)
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- if (list_empty(&_stp_pool_q)) {
+ if (unlikely(list_empty(&_stp_pool_q))) {
spin_unlock_irqrestore(&_stp_pool_lock, flags);
+ dbug("_stp_pool_q empty\n");
return -1;
}
@@ -187,12 +262,54 @@ static int _stp_ctl_write (int type, void *data, int len)
/* put it on the pool of ready buffers */
numtrylock = 0;
- while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
+ while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
+
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- list_add_tail(&bptr->list, &_stp_ready_q);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+
+ list_add_tail(&bptr->list, &_stp_ctl_ready_q);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
+
+ return len;
+}
+
+static int _stp_sym_write (int type, void *data, unsigned len)
+{
+ struct _stp_buffer *bptr;
+ unsigned long flags;
+
+#ifdef DEBUG
+ _stp_sym_write_dbug(type, data, len);
+#endif
+
+ /* make sure we won't overflow the buffer */
+ if (unlikely(len > STP_BUFFER_SIZE))
+ return 0;
+
+ spin_lock_irqsave (&_stp_pool_lock, flags);
+ if (unlikely(list_empty(&_stp_pool_q))) {
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+ dbug("_stp_pool_q empty\n");
+ return -1;
+ }
+
+ /* get the next buffer from the pool */
+ bptr = (struct _stp_buffer *)_stp_pool_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ bptr->type = type;
+ memcpy(bptr->buf, data, len);
+ bptr->len = len;
+
+ /* put it on the pool of ready buffers */
+ spin_lock_irqsave (&_stp_sym_ready_lock, flags);
+ list_add_tail(&bptr->list, &_stp_sym_ready_q);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* OK, it's queued. Now signal any waiters. */
+ wake_up_interruptible(&_stp_sym_wq);
return len;
}
@@ -201,45 +318,89 @@ static int _stp_ctl_write (int type, void *data, int len)
static int _stp_ctl_send (int type, void *data, int len)
{
int err, trylimit = 50;
- kbug("ctl_send: type=%d len=%d\n", type, len);
- while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
- msleep (5);
- kbug("returning %d\n", err);
+ if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) {
+ while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ } else {
+ while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ }
return err;
}
static ssize_t
-_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+_stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct _stp_buffer *bptr;
int len;
unsigned long flags;
- /* FIXME FIXME FIXME. assuming count is large enough to hold buffer!! */
+ /* wait for nonempty ready queue */
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ while (list_empty(&_stp_sym_ready_q)) {
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ if (wait_event_interruptible(_stp_sym_wq, !list_empty(&_stp_sym_ready_q)))
+ return -ERESTARTSYS;
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ }
+
+ /* get the next buffer off the ready list */
+ bptr = (struct _stp_buffer *)_stp_sym_ready_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* write it out */
+ len = bptr->len + 4;
+ if (len > count || copy_to_user(buf, &bptr->type, len)) {
+ /* now what? We took it off the queue then failed to send it */
+ /* we can't put it back on the queue because it will likely be out-of-order */
+ /* fortunately this should never happen */
+ /* FIXME need to mark this as a transport failure */
+ errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
+ return -EFAULT;
+ }
+
+ /* put it on the pool of free buffers */
+ spin_lock_irqsave(&_stp_pool_lock, flags);
+ list_add_tail(&bptr->list, &_stp_pool_q);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ return len;
+}
+
+static ssize_t
+_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct _stp_buffer *bptr;
+ int len;
+ unsigned long flags;
/* wait for nonempty ready queue */
- spin_lock_irqsave(&_stp_ready_lock, flags);
- while (list_empty(&_stp_ready_q)) {
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
+ while (list_empty(&_stp_ctl_ready_q)) {
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ready_q)))
+ if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ctl_ready_q)))
return -ERESTARTSYS;
- spin_lock_irqsave(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
}
/* get the next buffer off the ready list */
- bptr = (struct _stp_buffer *)_stp_ready_q.next;
+ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.next;
list_del_init(&bptr->list);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
/* write it out */
len = bptr->len + 4;
- if (copy_to_user(buf, &bptr->type, len)) {
+ if (len > count || copy_to_user(buf, &bptr->type, len)) {
/* now what? We took it off the queue then failed to send it */
/* we can't put it back on the queue because it will likely be out-of-order */
/* fortunately this should never happen */
/* FIXME need to mark this as a transport failure */
+ errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
return -EFAULT;
}
@@ -251,9 +412,28 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
return len;
}
+static int _stp_sym_opens = 0;
+static int _stp_sym_open_cmd (struct inode *inode, struct file *file)
+{
+ /* only allow one reader */
+ if (_stp_sym_opens)
+ return -1;
+
+ _stp_sym_opens++;
+ return 0;
+}
+
+static int _stp_sym_close_cmd (struct inode *inode, struct file *file)
+{
+ if (_stp_sym_opens)
+ _stp_sym_opens--;
+ return 0;
+}
+
static int _stp_ctl_opens = 0;
static int _stp_ctl_open_cmd (struct inode *inode, struct file *file)
{
+ /* only allow one reader */
if (_stp_ctl_opens)
return -1;
@@ -277,6 +457,13 @@ static struct file_operations _stp_proc_fops_cmd = {
.open = _stp_ctl_open_cmd,
.release = _stp_ctl_close_cmd,
};
+static struct file_operations _stp_sym_fops_cmd = {
+ .owner = THIS_MODULE,
+ .read = _stp_sym_read_cmd,
+ .write = _stp_sym_write_cmd,
+ .open = _stp_sym_open_cmd,
+ .release = _stp_sym_close_cmd,
+};
/* copy since proc_match is not MODULE_EXPORT'd */
static int my_proc_match(int len, const char *name, struct proc_dir_entry *de)
@@ -351,7 +538,8 @@ static int _stp_register_ctl_channel (void)
struct proc_dir_entry *de, *bs = NULL;
struct list_head *p, *tmp;
- INIT_LIST_HEAD(&_stp_ready_q);
+ INIT_LIST_HEAD(&_stp_ctl_ready_q);
+ INIT_LIST_HEAD(&_stp_sym_ready_q);
INIT_LIST_HEAD(&_stp_pool_q);
/* allocate buffers */
@@ -387,15 +575,23 @@ static int _stp_register_ctl_channel (void)
bs = create_proc_read_entry("bufsize", 0, _stp_proc_root, _stp_ctl_read_bufsize, NULL);
#endif /* STP_BULKMODE */
- /* finally create /proc/systemtap/module_name/cmd */
- de = create_proc_entry ("cmd", 0600, _stp_proc_root);
+ /* create /proc/systemtap/module_name/.cmd */
+ de = create_proc_entry (".cmd", 0600, _stp_proc_root);
if (de == NULL)
goto err1;
de->uid = _stp_uid;
de->gid = _stp_gid;
de->proc_fops = &_stp_proc_fops_cmd;
- return 0;
+ /* create /proc/systemtap/module_name/.symbols */
+ de = create_proc_entry (".symbols", 0600, _stp_proc_root);
+ if (de == NULL)
+ goto err2;
+ de->proc_fops = &_stp_sym_fops_cmd;
+
+ return 0;
+err2:
+ remove_proc_entry (".cmd", _stp_proc_root);
err1:
#ifdef STP_BULKMODE
for (de = _stp_proc_root->subdir; de; de = de->next)
@@ -439,7 +635,8 @@ static void _stp_unregister_ctl_channel (void)
remove_proc_entry ("bufsize", _stp_proc_root);
#endif /* STP_BULKMODE */
- remove_proc_entry ("cmd", _stp_proc_root);
+ remove_proc_entry (".symbols", _stp_proc_root);
+ remove_proc_entry (".cmd", _stp_proc_root);
_stp_rmdir_proc_module();
/* free memory pools */
@@ -447,7 +644,11 @@ static void _stp_unregister_ctl_channel (void)
list_del(p);
kfree(p);
}
- list_for_each_safe(p, tmp, &_stp_ready_q) {
+ list_for_each_safe(p, tmp, &_stp_sym_ready_q) {
+ list_del(p);
+ kfree(p);
+ }
+ list_for_each_safe(p, tmp, &_stp_ctl_ready_q) {
list_del(p);
kfree(p);
}
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 507cd1ad..d44d6851 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -66,22 +66,20 @@ static struct workqueue_struct *_stp_wq;
#include "control.c"
#endif
-void _stp_ask_for_symbols(void)
+static void _stp_ask_for_symbols(void)
{
struct _stp_msg_symbol req;
struct _stp_module mod;
- /* ask for symbols, modules, and send transport info */
+ /* ask for symbols and modules */
kbug("AFS\n");
req.endian = 0x1234;
req.ptr_size = sizeof(char *);
_stp_ctl_send(STP_SYMBOLS, &req, sizeof(req));
-
+
strcpy(mod.name, "");
_stp_ctl_send(STP_MODULE, &mod, sizeof(mod));
-
- _stp_ctl_send(STP_TRANSPORT, NULL, 0);
}
/*
@@ -156,11 +154,10 @@ static void _stp_work_queue (void *data)
int do_io = 0;
unsigned long flags;
- spin_lock_irqsave(&_stp_ready_lock, flags);
- if (!list_empty(&_stp_ready_q))
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
+ if (!list_empty(&_stp_ctl_ready_q))
do_io = 1;
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
-
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
if (do_io)
wake_up_interruptible(&_stp_ctl_wq);
diff --git a/tapsets.cxx b/tapsets.cxx
index 2af94890..379bb265 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -26,6 +26,7 @@
#include <vector>
#include <cstdarg>
#include <cassert>
+#include <iomanip>
extern "C" {
#include <fcntl.h>
@@ -712,7 +713,7 @@ struct dwflpp
{}
- void setup(bool kernel)
+ void setup(bool kernel, bool debuginfo_needed = true)
{
// XXX: this is where the session -R parameter could come in
static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug";
@@ -741,11 +742,12 @@ struct dwflpp
throw semantic_error ("cannot open dwfl");
dwfl_report_begin (dwfl);
- dwfl_assert ("missing kernel debuginfo",
- dwfl_linux_kernel_report_offline
- (dwfl,
- sess.kernel_release.c_str(),
- NULL /* selection predicate */));
+ int rc = dwfl_linux_kernel_report_offline (dwfl,
+ sess.kernel_release.c_str(),
+ /* selection predicate */
+ NULL);
+ if (debuginfo_needed)
+ dwfl_assert ("missing kernel debuginfo", rc);
// XXX: it would be nice if we could do a single
// ..._report_offline call for an entire systemtap script, so
@@ -5008,11 +5010,45 @@ mark_query::mark_query(systemtap_session & sess,
assert (has_mark_str);
}
-struct markers_data
+void
+hex_dump(unsigned char *data, size_t len)
{
- string name;
- string params;
-};
+ // Dump data
+ size_t idx = 0;
+ while (idx < len)
+ {
+ string char_rep;
+
+ clog << " 0x" << setfill('0') << setw(8) << hex << internal << idx;
+
+ for (int i = 0; i < 4; i++)
+ {
+ clog << " ";
+ size_t limit = idx + 4;
+ while (idx < len && idx < limit)
+ {
+ clog << setfill('0') << setw(2)
+ << ((unsigned) *((unsigned char *)data + idx));
+ if (isprint(*((char *)data + idx)))
+ char_rep += *((char *)data + idx);
+ else
+ char_rep += '.';
+ idx++;
+ }
+ while (idx < limit)
+ {
+ clog << " ";
+ idx++;
+ }
+ }
+ clog << " " << char_rep << dec << setfill(' ') << endl;
+ }
+}
+
+struct __mark_marker {
+ char *name;
+ char *format;
+} __attribute__((aligned(8)));
void
mark_query::handle_query_module()
@@ -5021,114 +5057,240 @@ mark_query::handle_query_module()
Elf *elf = dwfl_module_getelf(dw.module, &baseaddr);
assert(elf);
- string section_name;
+ GElf_Addr start_markers_addr = 0;
+ GElf_Addr stop_markers_addr = 0;
+ int syments = dwfl_module_getsymtab(dw.module);
+ assert(syments);
+
size_t shstrndx;
dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
- // Find markers string section ("__markers_strings")
+ // Try to find the markers section (named "__markers") and use its
+ // extents for the start and stop marker addresses.
Elf_Scn *scn = NULL;
- Elf_Scn *markers_string_scn = NULL;
while ((scn = elf_nextscn (elf, scn)) != NULL)
{
- // Handle the section if it is a string/progbits section.
GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ GElf_Shdr *shdr;
+ // Handle the section if it is a progbits section.
+ shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL && shdr->sh_type == SHT_PROGBITS)
{
- section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
- if (section_name == "__markers_strings")
+ string section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (section_name == "__markers")
{
- markers_string_scn = scn;
+ start_markers_addr = shdr->sh_addr;
+ stop_markers_addr = shdr->sh_addr + shdr->sh_size;
break;
}
}
}
- // If this module doesn't have a markers string section, just
- // return. Code above this will report an error if necessary.
- if (markers_string_scn == NULL)
- return;
-
- // Get the string section data now.
- Elf_Data *data = elf_getdata(markers_string_scn, NULL);
- if (data == NULL)
- throw semantic_error("no __markers_string data?");
-
- // Process each marker. For each marker, there should be 2 strings
- // in the __markers_string section: the marker name string and the
- // marker parameter type list string.
- size_t offset = 0;
- vector<markers_data *> markers;
- while (offset < data->d_size)
+ // If we haven't found the start and stop marker addresses, look for
+ // the start and stop marker symbols.
+ if (start_markers_addr == 0 || stop_markers_addr == 0)
{
- // Grab the marker name
- if (offset >= data->d_size)
- throw semantic_error("bad __markers_string section?");
- string name = (char *)(data->d_buf) + offset;
- offset += name.size() + 1;
- if (offset >= data->d_size || name.empty())
- throw semantic_error("bad __markers_string section?");
-
- // Skip any '\0' chars
- while (offset < data->d_size)
+ for (int i = 1; i < syments; ++i)
{
- if (*((char *)(data->d_buf) + offset) != '\0')
- break;
- offset++;
+ GElf_Sym sym;
+ const char *name = dwfl_module_getsym(dw.module, i, &sym, NULL);
+ if (name != NULL
+ // if it is a NOTYPE GLOBAL
+ && sym.st_info == GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE)
+ // and it has default visibility rules,
+ && GELF_ST_VISIBILITY(sym.st_other) == STV_DEFAULT
+ // and its size is 0
+ && sym.st_size == 0)
+ {
+ if (start_markers_addr == 0
+ && strcmp(name, "__start___markers") == 0)
+ {
+ start_markers_addr = sym.st_value;
+ if (stop_markers_addr != 0)
+ break;
+ }
+ else if (stop_markers_addr == 0
+ && strcmp(name, "__stop___markers") == 0)
+ {
+ stop_markers_addr = sym.st_value;
+ if (start_markers_addr != 0)
+ break;
+ }
+ }
}
+ }
- // Grab the parameter string.
- string params = (char *)(data->d_buf) + offset;
- offset += params.size() + 1;
- if (offset >= data->d_size)
- throw semantic_error("bad __markers_string section?");
+ if (sess.verbose > 2)
+ clog << "__start___markers: 0x" << hex << start_markers_addr << endl
+ << "__stop___markers: 0x" << hex << stop_markers_addr << dec << endl;
- // Skip any '\0' chars
- while (offset < data->d_size)
- {
- if (*((char *)(data->d_buf) + offset) != '\0')
- break;
- offset++;
- }
+ // If we couldn't find the start and stop markers address, just
+ // return. Code above this will report an error if necessary.
+ if (start_markers_addr == 0 || stop_markers_addr == 0)
+ return;
- // Skip the arg string
- while (offset < data->d_size)
+ GElf_Xword marker_sym_size = 0;
+ Elf_Scn *marker_data_scn = NULL;
+ GElf_Shdr marker_data_shdr_mem;
+ GElf_Shdr *marker_data_shdr = NULL;
+ Elf_Data *marker_data_data = NULL;
+ Elf_Scn *marker_string_scn = NULL;
+ GElf_Shdr marker_string_shdr_mem;
+ GElf_Shdr *marker_string_shdr = NULL;
+ Elf_Data *marker_string_data = NULL;
+ map<string, string> markers;
+
+ // Now we know starting/ending addresses of all marker symbols. Find
+ // all marker symbols.
+ for (int i = 1; i < syments; ++i)
+ {
+ GElf_Sym sym;
+ GElf_Word shndxp;
+
+ const char *name = dwfl_module_getsym(dw.module, i, &sym, &shndxp);
+ if (name != NULL
+ // if it is a LOCAL OBJECT
+ && sym.st_info == GELF_ST_INFO(STB_LOCAL, STT_OBJECT)
+ // and it has default visibility rules,
+ && GELF_ST_VISIBILITY(sym.st_other) == STV_DEFAULT
+ // and its value is between start_marker_value and
+ // stop_marker_value
+ && sym.st_value >= start_markers_addr
+ && sym.st_value < stop_markers_addr)
{
- if (*((char *)(data->d_buf) + offset) == '\0')
- break;
- offset++;
- }
- offset++;
+ // Remember the marker size - all marker structs are the
+ // same size.
+ if (marker_sym_size == 0)
+ marker_sym_size = sym.st_size;
+
+ if (sess.verbose > 2)
+ clog << endl << setw(6) << dec << i << ": "
+ << setfill('0') << setw(8) << hex << sym.st_value
+ << " "
+ << setfill(' ') << setw(5) << hex << sym.st_size << dec
+ << " " << name << endl;
+
+ // Since all marker data lives in the same section, we'll
+ // just grab the section from the first marker we find.
+ if (marker_data_scn == NULL)
+ {
+ marker_data_scn = elf_getscn (elf, shndxp);
+ if (marker_data_scn == NULL)
+ throw semantic_error("couldn't get section "
+ + lex_cast<string>(shndxp));
+
+ // Get the marker data section header
+ marker_data_shdr = gelf_getshdr (marker_data_scn,
+ &marker_data_shdr_mem);
+ if (marker_data_shdr == NULL)
+ throw semantic_error("couldn't get section header for section "
+ + lex_cast<string>(shndxp));
+
+ if (sess.verbose > 2)
+ clog << "section addr: " << setw(8) << setfill('0') << hex
+ << marker_data_shdr->sh_addr
+ << dec << setfill(' ') << endl;
+
+ // Get the data of the section.
+ marker_data_data = elf_getdata (marker_data_scn,
+ NULL);
+ if (marker_data_data == NULL)
+ throw semantic_error("couldn't get section data in section "
+ + lex_cast<string>(shndxp));
+ }
- // Skip any '\0' chars
- while (offset < data->d_size)
- {
- if (*((char *)(data->d_buf) + offset) != '\0')
- break;
- offset++;
+ GElf_Addr offset = sym.st_value - marker_data_shdr->sh_addr;
+ if (sess.verbose > 2)
+ clog << "value: "
+ << setw(8) << setfill('0') << hex << sym.st_value
+ << " section addr: " << setw(8) << marker_data_shdr->sh_addr
+ << " section offset: " << setw(8) << offset
+ << setfill(' ') << dec << endl;
+
+ if ((offset + marker_sym_size) <= marker_data_shdr->sh_size)
+ {
+ if (sess.verbose > 2)
+ hex_dump((unsigned char *)marker_data_data->d_buf + offset,
+ marker_sym_size);
+
+ struct __mark_marker *mark = ((struct __mark_marker *)((unsigned char *)marker_data_data->d_buf + offset));
+ if (sess.verbose > 2)
+ clog << "Dump of marker:" << endl
+ << " name: 0x"
+ << setfill('0') << setw(8) << hex << (unsigned int)mark->name << endl
+ << " format: 0x"
+ << setw(8) << (unsigned int)mark->format
+ << setfill(' ') << dec << endl;
+
+ // Since all marker string data lives in the same
+ // section, we'll just grab the section from the first
+ // marker string we find.
+ if (marker_string_data == NULL)
+ {
+ bool found = false;
+ while ((marker_string_scn = elf_nextscn (elf, marker_string_scn)) != NULL)
+ {
+ // Handle the section if it is a progbits section.
+ marker_string_shdr = gelf_getshdr (marker_string_scn,
+ &marker_string_shdr_mem);
+ if (marker_string_shdr != NULL
+ && marker_string_shdr->sh_type == SHT_PROGBITS
+ && (GElf_Addr)(uint)mark->name >= marker_string_shdr->sh_addr
+ && (GElf_Addr)(uint)mark->name < (marker_string_shdr->sh_addr + marker_string_shdr->sh_size))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (! found)
+ throw semantic_error("cannot find marker string section");
+
+ marker_string_data = elf_getdata(marker_string_scn, NULL);
+ if (marker_string_data == NULL)
+ throw semantic_error("cannot get marker string section data");
+ }
+
+ GElf_Addr offset = (GElf_Addr)(uint)mark->name
+ - marker_string_shdr->sh_addr;
+ char *name = NULL;
+ char *format = NULL;
+ if ((GElf_Addr)(uint)mark->name >= marker_string_shdr->sh_addr
+ && offset < marker_string_shdr->sh_size)
+ {
+ name = (char *)(marker_string_data->d_buf) + offset;
+ if (sess.verbose > 2)
+ clog << " name: " << name << endl;
+ }
+
+ offset = (GElf_Addr)(uint)mark->format
+ - marker_string_shdr->sh_addr;
+ if ((GElf_Addr)(uint)mark->format >= marker_string_shdr->sh_addr
+ && offset < marker_string_shdr->sh_size)
+ {
+ format = (char *)(marker_string_data->d_buf) + offset;
+ if (sess.verbose > 2)
+ clog << " format: " << format << endl;
+ }
+
+ if (name != NULL && format != NULL)
+ markers[name] = format;
+ }
}
-
- markers_data *m = new markers_data;
- m->name = name;
- m->params = params;
- markers.push_back(m);
}
// Search marker list for matching markers
- for (size_t i = 0; i < markers.size(); i++)
+ for (map<string,string>::iterator it = markers.begin(); it != markers.end(); it++)
{
- const markers_data *m = markers.at(i);
-
// Below, "rc" has negative polarity: zero iff matching. Also,
// we don't have to worry about the module not matching. If it
// didn't match, this function wouldn't get called.
- int rc = fnmatch(mark_str_val.c_str(), m->name.c_str(), 0);
+ int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
if (! rc)
{
derived_probe *dp
= new mark_derived_probe (sess,
- m->name, m->params,
+ it->first, it->second,
module_val,
base_probe);
results.push_back (dp);
@@ -5221,7 +5383,7 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s,
require <block*> (&v, &(this->body), base->body);
target_symbol_seen = v.target_symbol_seen;
- if (sess.verbose > 1)
+ if (sess.verbose > 2)
clog << "marker-based " << name << " signature=" << probe_sig << endl;
}
@@ -5584,7 +5746,7 @@ mark_builder::build(systemtap_session & sess,
{
kern_dw = new dwflpp(sess);
assert(kern_dw);
- kern_dw->setup(true);
+ kern_dw->setup(true, false);
}
mark_query mq(sess, base, location, *kern_dw, parameters, finished_results);
diff --git a/testsuite/systemtap.syscall/ChangeLog b/testsuite/systemtap.syscall/ChangeLog
index 69d77c85..1d234d3a 100644
--- a/testsuite/systemtap.syscall/ChangeLog
+++ b/testsuite/systemtap.syscall/ChangeLog
@@ -1,3 +1,6 @@
+2007-10-12 David Wilder <dwilder@us.ibm.com>
+ * timer.c: init tid to 0 to workaround bug on s390x.
+
2007-10-11 David Wilder <dwilder@us.ibm.com>
* futimes.c: Only test system calls that have
diff --git a/testsuite/systemtap.syscall/timer.c b/testsuite/systemtap.syscall/timer.c
index c9553c82..f7b888ae 100644
--- a/testsuite/systemtap.syscall/timer.c
+++ b/testsuite/systemtap.syscall/timer.c
@@ -9,7 +9,7 @@
int main()
{
- timer_t tid;
+ timer_t tid=0;
struct itimerspec val, oval;
syscall(SYS_timer_create, CLOCK_REALTIME, NULL, &tid);