diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | runtime/staprun/ChangeLog | 15 | ||||
-rw-r--r-- | runtime/staprun/cap.c | 4 | ||||
-rw-r--r-- | runtime/staprun/ctl.c | 13 | ||||
-rw-r--r-- | runtime/staprun/mainloop.c | 2 | ||||
-rw-r--r-- | runtime/staprun/staprun.c | 5 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 10 | ||||
-rw-r--r-- | runtime/staprun/staprun_funcs.c | 46 | ||||
-rw-r--r-- | runtime/staprun/symbols.c | 13 | ||||
-rw-r--r-- | runtime/transport/ChangeLog | 10 | ||||
-rw-r--r-- | runtime/transport/control.c | 252 | ||||
-rw-r--r-- | runtime/transport/procfs.c | 299 | ||||
-rw-r--r-- | runtime/transport/transport.c | 15 | ||||
-rw-r--r-- | tapsets.cxx | 330 | ||||
-rw-r--r-- | testsuite/systemtap.syscall/ChangeLog | 3 | ||||
-rw-r--r-- | testsuite/systemtap.syscall/timer.c | 2 |
18 files changed, 821 insertions, 220 deletions
@@ -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); |