summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2009-11-03 16:22:36 -0500
committerDave Brolley <brolley@redhat.com>2009-11-03 16:22:36 -0500
commit899b66209b0146560f0efc33efe58a4be3577df3 (patch)
tree7b64764b917c359a99d0adcf6c68a2d73cd52be7 /runtime
parentd4ad7984018ff769cbb662342be7e501632c0bea (diff)
parent89651893a8ec51ee4d77ddfd57019e350ad7b169 (diff)
downloadsystemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.tar.gz
systemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.tar.xz
systemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.zip
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
Conflicts: Makefile.in configure doc/Makefile.in doc/SystemTap_Tapset_Reference/Makefile.in grapher/Makefile.in testsuite/configure
Diffstat (limited to 'runtime')
-rw-r--r--runtime/probe_lock.h68
-rw-r--r--runtime/staprun/mainloop.c26
-rw-r--r--runtime/staprun/staprun.h2
-rw-r--r--runtime/stat-common.c2
-rw-r--r--runtime/string.c6
-rw-r--r--runtime/task_finder.c4
-rw-r--r--runtime/transport/transport.c38
-rw-r--r--runtime/transport/transport.h3
-rw-r--r--runtime/unwind.c43
-rw-r--r--runtime/unwind/unwind.h6
10 files changed, 155 insertions, 43 deletions
diff --git a/runtime/probe_lock.h b/runtime/probe_lock.h
new file mode 100644
index 00000000..1915d4ff
--- /dev/null
+++ b/runtime/probe_lock.h
@@ -0,0 +1,68 @@
+/* probe locking header file
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _PROBE_LOCK_H
+#define _PROBE_LOCK_H
+
+#include <linux/spinlock.h>
+
+// XXX: old 2.6 kernel hack
+#ifndef read_trylock
+#define read_trylock(x) ({ read_lock(x); 1; })
+#endif
+
+struct stp_probe_lock {
+ #ifdef STP_TIMING
+ atomic_t *skipped;
+ #endif
+ rwlock_t *lock;
+ unsigned write_p;
+};
+
+
+static void
+stp_unlock_probe(const struct stp_probe_lock *locks, unsigned num_locks)
+{
+ unsigned i;
+ for (i = num_locks; i-- > 0;) {
+ if (locks[i].write_p)
+ write_unlock(locks[i].lock);
+ else
+ read_unlock(locks[i].lock);
+ }
+}
+
+
+static unsigned
+stp_lock_probe(const struct stp_probe_lock *locks, unsigned num_locks)
+{
+ unsigned i, numtrylock = 0;
+ for (i = 0; i < num_locks; ++i) {
+ if (locks[i].write_p)
+ while (!write_trylock(locks[i].lock) &&
+ (++numtrylock < MAXTRYLOCK))
+ ndelay (TRYLOCKDELAY);
+ else
+ while (!read_trylock(locks[i].lock) &&
+ (++numtrylock < MAXTRYLOCK))
+ ndelay (TRYLOCKDELAY);
+ if (unlikely(numtrylock >= MAXTRYLOCK)) {
+ atomic_inc(&skipped_count);
+ #ifdef STP_TIMING
+ atomic_inc(locks[i].skipped);
+ #endif
+ stp_unlock_probe(locks, i);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+#endif /* _PROBE_LOCK_H */
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index cf8bef9a..ab228937 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -38,7 +38,7 @@ static void *signal_thread(void *arg)
}
dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
if (signum == SIGQUIT)
- cleanup_and_exit(1);
+ cleanup_and_exit(1, 0);
else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) {
// send STP_EXIT
rc = write(control_channel, &btype, sizeof(btype));
@@ -383,7 +383,7 @@ int init_stapio(void)
/* cleanup_and_exit() closed channels, frees memory,
* removes the module (if necessary) and exits. */
-void cleanup_and_exit(int detach)
+void cleanup_and_exit(int detach, int rc)
{
static int exiting = 0;
const char *staprun;
@@ -467,7 +467,7 @@ void cleanup_and_exit(int detach)
}
if (WIFEXITED(rstatus)) {
- _exit(WEXITSTATUS(rstatus)); /* only possibility for rc=0 exit */
+ _exit(rc ?: WEXITSTATUS(rstatus));
}
_exit(-1);
}
@@ -484,8 +484,9 @@ int stp_main_loop(void)
uint32_t type;
FILE *ofp = stdout;
char recvbuf[8196];
+ int error_detected = 0;
- setvbuf(ofp, (char *)NULL, _IOLBF, 0);
+ setvbuf(ofp, (char *)NULL, _IONBF, 0);
setup_main_signals();
dbug(2, "in main loop\n");
@@ -511,18 +512,21 @@ int stp_main_loop(void)
case STP_REALTIME_DATA:
if (write_realtime_data(data, nb)) {
_perr("write error (nb=%ld)", (long)nb);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
break;
#endif
case STP_OOB_DATA:
eprintf("%s", (char *)data);
+ if (strncmp(data, "ERROR:", 5) == 0){
+ error_detected = 1;
+ }
break;
case STP_EXIT:
{
/* module asks us to unload it and exit */
dbug(2, "got STP_EXIT\n");
- cleanup_and_exit(0);
+ cleanup_and_exit(0, error_detected);
break;
}
case STP_REQUEST_EXIT:
@@ -540,7 +544,7 @@ int stp_main_loop(void)
if (t->res < 0) {
if (target_cmd)
kill(target_pid, SIGKILL);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
} else if (target_cmd) {
dbug(1, "detaching pid %d\n", target_pid);
#if WORKAROUND_BZ467568
@@ -555,7 +559,7 @@ int stp_main_loop(void)
perror ("ptrace detach");
if (target_cmd)
kill(target_pid, SIGKILL);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
#endif
}
@@ -573,15 +577,15 @@ int stp_main_loop(void)
struct _stp_msg_start ts;
if (use_old_transport) {
if (init_oldrelayfs() < 0)
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
} else {
if (init_relayfs() < 0)
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
ts.target = target_pid;
send_request(STP_START, &ts, sizeof(ts));
if (load_only)
- cleanup_and_exit(1);
+ cleanup_and_exit(1, 0);
break;
}
default:
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index f9f01003..9cdbc861 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -114,7 +114,7 @@ int init_staprun(void);
int init_stapio(void);
int stp_main_loop(void);
int send_request(int type, void *data, int len);
-void cleanup_and_exit (int);
+void cleanup_and_exit (int, int);
int init_ctl_channel(const char *name, int verb);
void close_ctl_channel(void);
int init_relayfs(void);
diff --git a/runtime/stat-common.c b/runtime/stat-common.c
index e6fd3a11..7123dc8e 100644
--- a/runtime/stat-common.c
+++ b/runtime/stat-common.c
@@ -270,7 +270,7 @@ static void _stp_stat_print_histogram_buf(char *buf, size_t size, Hist st, stat
for (j = 0; j < v; ++j)
HIST_PRINTF("@");
- HIST_PRINTF("%*lld\n", HIST_WIDTH - v + 1 + cnt_space, sd->histogram[i]);
+ HIST_PRINTF("%*lld\n", (int)(HIST_WIDTH - v + 1 + cnt_space), sd->histogram[i]);
}
HIST_PRINTF("\n");
#undef HIST_PRINTF
diff --git a/runtime/string.c b/runtime/string.c
index cdafbf64..b3f81f0e 100644
--- a/runtime/string.c
+++ b/runtime/string.c
@@ -21,7 +21,11 @@
*/
/** Sprintf into a string.
- * Like printf, except output goes into a string.
+ * Like printf, except output goes into a string.
+ *
+ * NB: these are script language printf formatting directives, where
+ * %d ints are 64-bits etc, so we can't use gcc level attribute printf
+ * to type-check the arguments.
*
* @param str string
* @param fmt A printf-style format string followed by a
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 6b50f1b9..e89ac8ee 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -87,15 +87,15 @@ struct stap_task_finder_target {
struct list_head callback_list_head;
struct list_head callback_list;
struct utrace_engine_ops ops;
+ size_t pathlen;
unsigned engine_attached:1;
unsigned mmap_events:1;
unsigned munmap_events:1;
unsigned mprotect_events:1;
- size_t pathlen;
/* public: */
- const char *procname;
pid_t pid;
+ const char *procname;
stap_task_finder_callback callback;
stap_task_finder_mmap_callback mmap_callback;
stap_task_finder_munmap_callback munmap_callback;
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index f5efce9f..bab5efa9 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -19,6 +19,7 @@
#include <linux/namei.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
static int _stp_exit_flag = 0;
@@ -30,6 +31,9 @@ static int _stp_ctl_attached = 0;
static pid_t _stp_target = 0;
static int _stp_probes_started = 0;
+static int _stp_exit_called = 0;
+static DEFINE_MUTEX(_stp_transport_mutex);
+
// For now, disable transport version 3 (unless STP_USE_RING_BUFFER is
// defined).
@@ -81,22 +85,26 @@ static struct workqueue_struct *_stp_wq;
static void _stp_handle_start(struct _stp_msg_start *st)
{
- dbug_trans(1, "stp_handle_start\n");
+ mutex_lock(&_stp_transport_mutex);
+ if (!_stp_exit_called) {
+ dbug_trans(1, "stp_handle_start\n");
#ifdef STAPCONF_VM_AREA
- { /* PR9740: workaround for kernel valloc bug. */
- void *dummy;
- dummy = alloc_vm_area (PAGE_SIZE);
- free_vm_area (dummy);
- }
+ { /* PR9740: workaround for kernel valloc bug. */
+ void *dummy;
+ dummy = alloc_vm_area (PAGE_SIZE);
+ free_vm_area (dummy);
+ }
#endif
- _stp_target = st->target;
- st->res = probe_start();
- if (st->res >= 0)
- _stp_probes_started = 1;
+ _stp_target = st->target;
+ st->res = probe_start();
+ if (st->res >= 0)
+ _stp_probes_started = 1;
- _stp_ctl_send(STP_START, st, sizeof(*st));
+ _stp_ctl_send(STP_START, st, sizeof(*st));
+ }
+ mutex_unlock(&_stp_transport_mutex);
}
/* common cleanup code. */
@@ -106,8 +114,7 @@ static void _stp_handle_start(struct _stp_msg_start *st)
/* when someone does /sbin/rmmod on a loaded systemtap module. */
static void _stp_cleanup_and_exit(int send_exit)
{
- static int _stp_exit_called = 0;
-
+ mutex_lock(&_stp_transport_mutex);
if (!_stp_exit_called) {
int failures;
@@ -135,6 +142,7 @@ static void _stp_cleanup_and_exit(int send_exit)
_stp_ctl_send(STP_EXIT, NULL, 0);
dbug_trans(1, "done with ctl_send STP_EXIT\n");
}
+ mutex_unlock(&_stp_transport_mutex);
}
static void _stp_request_exit(void)
@@ -293,7 +301,7 @@ err0:
static inline void _stp_lock_inode(struct inode *inode)
{
-#ifdef DEFINE_MUTEX
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
mutex_lock(&inode->i_mutex);
#else
down(&inode->i_sem);
@@ -302,7 +310,7 @@ static inline void _stp_lock_inode(struct inode *inode)
static inline void _stp_unlock_inode(struct inode *inode)
{
-#ifdef DEFINE_MUTEX
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
mutex_unlock(&inode->i_mutex);
#else
up(&inode->i_sem);
diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h
index 871e37b3..ddd85495 100644
--- a/runtime/transport/transport.h
+++ b/runtime/transport/transport.h
@@ -13,9 +13,6 @@
static int _stp_ctl_write(int type, void *data, unsigned len);
-static int _stp_transport_init(void);
-static void _stp_transport_close(void);
-
/* STP_CTL_BUFFER_SIZE is the maximum size of a message */
/* exchanged on the control channel. */
#if STP_TRANSPORT_VERSION == 1
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 00108a39..7607770e 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -88,7 +88,7 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
/* given an FDE, find its CIE */
static const u32 *cie_for_fde(const u32 *fde, void *unwind_data,
- int is_ehframe)
+ uint32_t table_len, int is_ehframe)
{
const u32 *cie;
@@ -118,6 +118,11 @@ static const u32 *cie_for_fde(const u32 *fde, void *unwind_data,
else
cie = unwind_data + fde[1];
+ /* Make sure address falls in the table */
+ if (((void *)cie) < ((void*)unwind_data)
+ || ((void*)cie) > ((void*)(unwind_data + table_len)))
+ return NULL;
+
if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
|| (*cie & (sizeof(*cie) - 1))
|| (cie[1] != 0xffffffff && cie[1] != 0)) {
@@ -200,7 +205,8 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy
return value;
}
-static signed fde_pointer_type(const u32 *cie)
+static signed fde_pointer_type(const u32 *cie, void *unwind_data,
+ uint32_t table_len)
{
const u8 *ptr = (const u8 *)(cie + 2);
unsigned version = *ptr;
@@ -212,11 +218,16 @@ static signed fde_pointer_type(const u32 *cie)
const u8 *end = (const u8 *)(cie + 1) + *cie;
uleb128_t len;
+ /* end of cie should fall within unwind table. */
+ if (((void*)end) < ((void *)unwind_data)
+ || ((void *)end) > ((void *)(unwind_data + table_len)))
+ return -1;
+
/* check if augmentation size is first (and thus present) */
if (*ptr != 'z')
return -1;
/* check if augmentation string is nul-terminated */
- if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
+ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
return -1;
++ptr; /* skip terminator */
get_uleb128(&ptr, end); /* skip code alignment */
@@ -267,6 +278,10 @@ static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value, s
}
}
+/* Limit the number of instructions we process. Arbitrary limit.
+ 512 should be enough for anybody... */
+#define MAX_CFI 512
+
static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, signed ptrType, struct unwind_state *state)
{
union {
@@ -276,6 +291,9 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
} ptr;
int result = 1;
+ if (end - start > MAX_CFI)
+ return 0;
+
dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc);
if (start != state->cieStart) {
state->loc = state->org;
@@ -606,10 +624,10 @@ static int unwind_frame(struct unwind_frame_info *frame,
/* found the fde, now set startLoc and endLoc */
if (fde != NULL) {
- cie = cie_for_fde(fde, table, is_ehframe);
+ cie = cie_for_fde(fde, table, table_len, is_ehframe);
if (likely(cie != NULL && cie != &bad_cie && cie != &not_fde)) {
ptr = (const u8 *)(fde + 2);
- ptrType = fde_pointer_type(cie);
+ ptrType = fde_pointer_type(cie, table, table_len);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
@@ -632,12 +650,12 @@ static int unwind_frame(struct unwind_frame_info *frame,
for (fde = table, tableSize = table_len; cie = NULL, tableSize > sizeof(*fde)
&& tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize);
- cie = cie_for_fde(fde, table, is_ehframe);
+ cie = cie_for_fde(fde, table, table_len, is_ehframe);
if (cie == &bad_cie) {
cie = NULL;
break;
}
- if (cie == NULL || cie == &not_fde || (ptrType = fde_pointer_type(cie)) < 0)
+ if (cie == NULL || cie == &not_fde || (ptrType = fde_pointer_type(cie, table, table_len)) < 0)
continue;
ptr = (const u8 *)(fde + 2);
@@ -666,6 +684,12 @@ static int unwind_frame(struct unwind_frame_info *frame,
state.cieEnd = ptr; /* keep here temporarily */
ptr = (const u8 *)(cie + 2);
end = (const u8 *)(cie + 1) + *cie;
+
+ /* end should fall within unwind table. */
+ if (((void *)end) < table
+ || ((void *)end) > ((void *)(table + table_len)))
+ goto err;
+
frame->call_frame = 1;
if ((state.version = *ptr) != 1) {
dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version);
@@ -723,6 +747,11 @@ static int unwind_frame(struct unwind_frame_info *frame,
state.cieEnd = end;
end = (const u8 *)(fde + 1) + *fde;
+ /* end should fall within unwind table. */
+ if (((void*)end) < table
+ || ((void *)end) > ((void *)(table + table_len)))
+ goto err;
+
/* skip augmentation */
if (((const char *)(cie + 2))[1] == 'z') {
uleb128_t augSize = get_uleb128(&ptr, end);
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
index 285a3a34..023ea603 100644
--- a/runtime/unwind/unwind.h
+++ b/runtime/unwind/unwind.h
@@ -143,8 +143,10 @@ static unsigned long read_pointer(const u8 **pLoc,
const void *end,
signed ptrType);
static const u32 bad_cie, not_fde;
-static const u32 *cie_for_fde(const u32 *fde, void *table, int is_ehframe);
-static signed fde_pointer_type(const u32 *cie);
+static const u32 *cie_for_fde(const u32 *fde, void *table,
+ uint32_t table_len, int is_ehframe);
+static signed fde_pointer_type(const u32 *cie,
+ void *table, uint32_t table_len);
#endif /* STP_USE_DWARF_UNWINDER */