summaryrefslogtreecommitdiffstats
path: root/runtime/staprun
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/staprun')
-rw-r--r--runtime/staprun/ChangeLog57
-rw-r--r--runtime/staprun/cap.c78
-rw-r--r--runtime/staprun/common.c46
-rw-r--r--runtime/staprun/ctl.c35
-rw-r--r--runtime/staprun/mainloop.c296
-rw-r--r--runtime/staprun/stapio.c17
-rw-r--r--runtime/staprun/staprun.c173
-rw-r--r--runtime/staprun/staprun.h10
-rw-r--r--runtime/staprun/staprun_funcs.c104
-rw-r--r--runtime/staprun/symbols.c333
-rw-r--r--runtime/staprun/unwind_data.c97
11 files changed, 505 insertions, 741 deletions
diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog
index e9ef2e2d..969c299d 100644
--- a/runtime/staprun/ChangeLog
+++ b/runtime/staprun/ChangeLog
@@ -1,3 +1,60 @@
+2008-05-05 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (child_proc): Handle sig_chld
+ in the proper thread.
+ (signal_thread): Don't call send_request()
+ because it isn't thread-safe.
+
+2008-05-05 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (signal_thread): New thread to handle signals
+ better.
+ (setup_main_signals): Create signal thread.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 6008
+ * common.c (parse_args): Increase the limitation of the buffer size
+ to 4095MB.
+ * common.c (usage): Ditto.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * stapio.c (main): Fix a typo in a debug message.
+ * staprun.c (main): Ditto.
+
+2008-04-24 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6451.
+ * common.c (control_channel): Initialize to -1.
+ * ctl.c (close_ctl_channel): Tolerate fd=0.
+
+2008-04-22 Martin Hunt <hunt@redhat.com>
+
+ * cap.c (init_cap): Detect capabilities failure and
+ run with them disabled.
+
+2008-04-22 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (send_request): Move here from common.c
+ staprun no longer send any messages.
+
+2008-04-22 hunt <hunt@redhat.com>
+
+ * common.c (usage): Add -d option.
+
+2008-04-21 Martin Hunt <hunt@redhat.com>
+
+ * staprun.c, stapio.c, staprun.h, mainloop.c, staprun_funcs.c,
+ ctl.c, common.c: Add "-d" option to have staprun remove
+ modules. Have staprun exec stapio and then have stapio
+ exec "staprun -d" to remove the module when finished.
+
+2008-04-16 Martin Hunt <hunt@redhat.com>
+
+ * ctl.c (init_ctl_channel): Remove unused parameter.
+ Just opens one channel now.
+
2008-02-21 David Smith <dsmith@redhat.com>
* staprun_funcs.c (check_path): Small security fix.
diff --git a/runtime/staprun/cap.c b/runtime/staprun/cap.c
index 6f22dfc9..6ac6701f 100644
--- a/runtime/staprun/cap.c
+++ b/runtime/staprun/cap.c
@@ -23,6 +23,8 @@
#include "staprun.h"
#include <sys/prctl.h>
+static int _stp_no_caps = 0;
+
/* like perror, but exits */
#define ferror(msg) { \
_perr(msg); \
@@ -54,10 +56,10 @@
* CAP_CHOWN - allows chown
*/
-int init_cap(void)
+void 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_DAC_OVERRIDE};
+ 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();
@@ -69,8 +71,11 @@ int init_cap(void)
if (cap_set_flag(caps, CAP_PERMITTED, numcaps, capv, CAP_SET) < 0)
ferror("cap_set_flag");
- if (cap_set_proc(caps) < 0)
- ferror("cap_set_proc");
+ if (cap_set_proc(caps) < 0) {
+ dbug(1, "Setting capabilities failed. Capabilities disabled.\n");
+ _stp_no_caps = 1;
+ return;
+ }
cap_free(caps);
@@ -82,8 +87,6 @@ int init_cap(void)
if (setresgid(gid, gid, gid) < 0)
ferror("setresgid");
-
- return 1;
}
void print_cap(char *text)
@@ -97,19 +100,18 @@ void print_cap(char *text)
perr("cap_get_proc");
return;
}
-
+
getresuid(&uid, &euid, &suid);
getresgid(&gid, &egid, &sgid);
printf("***** %s\n", text);
- if ((p=prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0)
+ if ((p = prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0)
perr("Couldn't get PR_SET_KEEPCAPS flag value");
- else
+ else
printf("KEEPCAPS: %d\n", p);
- printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n",
- uid, euid, suid, gid, egid, sgid );
+ printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n", uid, euid, suid, gid, egid, sgid);
printf("Caps: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
printf("*****\n\n");
@@ -121,38 +123,44 @@ void print_cap(char *text)
*/
void drop_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0)
- ferror("Could not clear effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0)
+ ferror("Could not clear effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
/* add_cap() adds a permitted capability to the effective set. */
void add_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
- ferror("Could not set effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
+ ferror("Could not set effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
/* del_cap() deletes a permitted capability from the effective set. */
void del_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0)
- ferror("Could not clear effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0)
+ ferror("Could not clear effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index 47778efd..93da51d8 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -22,6 +22,7 @@ unsigned int buffer_size;
char *target_cmd;
char *outfile_name;
int attach_mod;
+int delete_mod;
int load_only;
int need_uprobes;
@@ -30,8 +31,7 @@ char *modname = NULL;
char *modpath = "";
char *modoptions[MAXMODOPTIONS];
-int initialized = 0;
-int control_channel = 0;
+int control_channel = -1; /* NB: fd==0 possible */
void parse_args(int argc, char **argv)
{
@@ -44,10 +44,11 @@ void parse_args(int argc, char **argv)
target_cmd = NULL;
outfile_name = NULL;
attach_mod = 0;
+ delete_mod = 0;
load_only = 0;
need_uprobes = 0;
- while ((c = getopt(argc, argv, "ALuvb:t:d:c:o:x:")) != EOF) {
+ while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:")) != EOF) {
switch (c) {
case 'u':
need_uprobes = 1;
@@ -57,8 +58,8 @@ void parse_args(int argc, char **argv)
break;
case 'b':
buffer_size = (unsigned)atoi(optarg);
- if (buffer_size < 1 || buffer_size > 64) {
- err("Invalid buffer size '%d' (should be 1-64).\n", buffer_size);
+ if (buffer_size < 1 || buffer_size > 4095) {
+ err("Invalid buffer size '%d' (should be 1-4095).\n", buffer_size);
usage(argv[0]);
}
break;
@@ -67,7 +68,8 @@ void parse_args(int argc, char **argv)
target_pid = atoi(optarg);
break;
case 'd':
- /* obsolete internal option used by stap */
+ /* delete module */
+ delete_mod = 1;
break;
case 'c':
target_cmd = optarg;
@@ -128,11 +130,14 @@ void usage(char *prog)
err("-o FILE Send output to FILE.\n");
err("-b buffer size The systemtap module specifies a buffer size.\n");
err(" Setting one here will override that value. The\n");
- err(" value should be an integer between 1 and 64\n");
+ err(" value should be an integer between 1 and 4095 \n");
err(" which be assumed to be the buffer size in MB.\n");
err(" That value will be per-cpu in bulk mode.\n");
err("-L Load module and start probes, then detach.\n");
err("-A Attach to loaded systemtap module.\n");
+ err("-d Delete a module. Only detached or unused modules\n");
+ err(" the user has permission to access will be deleted. Use \"*\"\n");
+ err(" (quoted) to delete all unused modules.\n");
err("MODULE can be either a module name or a module path. If a\n");
err("module name is used, it is looked for in the following\n");
err("directory: /lib/modules/`uname -r`/systemtap\n");
@@ -250,10 +255,7 @@ static void fatal_handler (int signum)
rc = write (STDERR_FILENO, ERR_MSG, sizeof(ERR_MSG));
rc = write (STDERR_FILENO, str, strlen(str));
rc = write (STDERR_FILENO, "\n", 1);
- if (initialized)
- _exit(3);
- else
- _exit(1);
+ _exit(1);
}
void setup_signals(void)
@@ -294,28 +296,6 @@ void setup_signals(void)
#endif
}
-/**
- * send_request - send request to kernel over control channel
- * @type: the relay-app command id
- * @data: pointer to the data to be sent
- * @len: length of the data to be sent
- *
- * Returns 0 on success, negative otherwise.
- */
-int send_request(int type, void *data, int len)
-{
- char buf[1024];
-
- /* Before doing memcpy, make sure 'buf' is big enough. */
- if ((len + 4) > (int)sizeof(buf)) {
- _err("exceeded maximum send_request size.\n");
- return -1;
- }
- memcpy(buf, &type, 4);
- memcpy(&buf[4], data, len);
- return write(control_channel, buf, len+4);
-}
-
/*
* set FD_CLOEXEC for any file descriptor
*/
diff --git a/runtime/staprun/ctl.c b/runtime/staprun/ctl.c
index af7e6c1a..4597bf72 100644
--- a/runtime/staprun/ctl.c
+++ b/runtime/staprun/ctl.c
@@ -12,45 +12,42 @@
#include "staprun.h"
-int init_ctl_channel(int symbols)
+int init_ctl_channel(const char *name, int verb)
{
- char *cname, buf[PATH_MAX];
+ char 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/%s", modname, cname))
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) {
+ if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/.cmd", name))
return -1;
} else {
old_transport = 1;
- if (sprintf_chk(buf, "/proc/systemtap/%s/%s", modname, cname))
+ if (sprintf_chk(buf, "/proc/systemtap/%s/.cmd", name))
return -1;
}
-
- dbug(2, "Opening %s\n", buf);
+
+ dbug(2, "Opening %s\n", buf);
control_channel = open(buf, O_RDWR);
if (control_channel < 0) {
- if (attach_mod && errno == ENOENT)
- err("ERROR: Can not attach. Module %s not running.\n", modname);
- else
- perr("Couldn't open control channel '%s'", buf);
+ if (verb) {
+ if (attach_mod && errno == ENOENT)
+ err("ERROR: Can not attach. Module %s not running.\n", name);
+ else
+ perr("Couldn't open control channel '%s'", buf);
+ }
return -1;
}
if (set_clexec(control_channel) < 0)
return -1;
-
+
return old_transport;
}
void close_ctl_channel(void)
{
- if (control_channel > 0) {
+ if (control_channel >= 0) {
close(control_channel);
- control_channel = 0;
+ control_channel = -1;
}
}
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index 2e0c3c5c..61963743 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -15,39 +15,98 @@
/* globals */
int ncpus;
-int use_old_transport = 0;
+static int use_old_transport = 0;
+//enum _stp_sig_type { sig_none, sig_done, sig_detach };
+//static enum _stp_sig_type got_signal = sig_none;
-static void sigproc(int signum)
+/**
+ * send_request - send request to kernel over control channel
+ * @type: the relay-app command id
+ * @data: pointer to the data to be sent
+ * @len: length of the data to be sent
+ *
+ * Returns 0 on success, negative otherwise.
+ */
+int send_request(int type, void *data, int len)
{
- dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
-
- if (signum == SIGCHLD) {
- pid_t pid = waitpid(-1, NULL, WNOHANG);
- if (pid != target_pid)
- return;
- send_request(STP_EXIT, NULL, 0);
- } else if (signum == SIGQUIT)
- cleanup_and_exit(2);
- else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM)
- send_request(STP_EXIT, NULL, 0);
+ char buf[1024];
+
+ /* Before doing memcpy, make sure 'buf' is big enough. */
+ if ((len + 4) > (int)sizeof(buf)) {
+ _err("exceeded maximum send_request size.\n");
+ return -1;
+ }
+ memcpy(buf, &type, 4);
+ memcpy(&buf[4], data, len);
+ return write(control_channel, buf, len + 4);
}
-static void setup_main_signals(int cleanup)
+static void *signal_thread(void *arg)
{
- struct sigaction a;
- memset(&a, 0, sizeof(a));
- sigfillset(&a.sa_mask);
- if (cleanup == 0) {
- a.sa_handler = sigproc;
- sigaction(SIGCHLD, &a, NULL);
- } else
- a.sa_handler = SIG_IGN;
- sigaction(SIGINT, &a, NULL);
- sigaction(SIGTERM, &a, NULL);
- sigaction(SIGHUP, &a, NULL);
- sigaction(SIGQUIT, &a, NULL);
+ sigset_t *s = (sigset_t *) arg;
+ int signum, rc, btype = STP_EXIT;
+
+ while (1) {
+ if (sigwait(s, &signum) < 0) {
+ _perr("sigwait");
+ continue;
+ }
+ dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
+ if (signum == SIGQUIT)
+ cleanup_and_exit(1);
+ else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) {
+ // send STP_EXIT
+ rc = write(control_channel, &btype, sizeof(btype));
+ break;
+ }
+ }
+ return NULL;
+}
+
+static void chld_proc(int signum)
+{
+ int32_t rc, btype = STP_EXIT;
+ dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum));
+ pid_t pid = waitpid(-1, NULL, WNOHANG);
+ if (pid != target_pid)
+ return;
+ // send STP_EXIT
+ rc = write(control_channel, &btype, sizeof(btype));
}
+static void setup_main_signals(void)
+{
+ pthread_t tid;
+ struct sigaction sa;
+ sigset_t *s = malloc(sizeof(*s));
+ if (!s) {
+ _perr("malloc failed");
+ exit(1);
+ }
+ sigfillset(s);
+ pthread_sigmask(SIG_SETMASK, s, NULL);
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGQUIT, &sa, NULL);
+
+ sa.sa_handler = chld_proc;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ sigemptyset(s);
+ sigaddset(s, SIGINT);
+ sigaddset(s, SIGTERM);
+ sigaddset(s, SIGHUP);
+ sigaddset(s, SIGQUIT);
+ pthread_sigmask(SIG_SETMASK, s, NULL);
+ if (pthread_create(&tid, NULL, signal_thread, s) < 0) {
+ _perr("failed to create thread");
+ exit(1);
+ }
+}
/*
* start_cmd forks the command given on the command line
@@ -75,7 +134,7 @@ void start_cmd(void)
a.sa_handler = SIG_IGN;
sigaction(SIGINT, &a, NULL);
- dbug (1, "execing target_cmd %s\n", target_cmd);
+ dbug(1, "execing target_cmd %s\n", target_cmd);
if ((pid = fork()) < 0) {
_perr("fork");
exit(1);
@@ -86,8 +145,8 @@ void start_cmd(void)
sigaction(SIGINT, &a, NULL);
/* commands we fork need to run at normal priority */
- setpriority (PRIO_PROCESS, 0, 0);
-
+ setpriority(PRIO_PROCESS, 0, 0);
+
/* wait here until signaled */
sigwait(&usrset, &signum);
@@ -107,11 +166,11 @@ void system_cmd(char *cmd)
{
pid_t pid;
- dbug (2, "system %s\n", cmd);
+ dbug(2, "system %s\n", cmd);
if ((pid = fork()) < 0) {
_perr("fork");
} else if (pid == 0) {
- setpriority (PRIO_PROCESS, 0, 0);
+ setpriority(PRIO_PROCESS, 0, 0);
if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0)
perr("%s", cmd);
_exit(1);
@@ -128,7 +187,7 @@ static void read_buffer_info(void)
if (!use_old_transport)
return;
- if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC)
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC)
return;
if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname))
@@ -152,7 +211,6 @@ static void read_buffer_info(void)
return;
}
-
/**
* init_stapio - initialize the app
* @print_summary: boolean, print summary or not at end of run
@@ -164,7 +222,7 @@ int init_stapio(void)
dbug(2, "init_stapio\n");
/* create control channel */
- use_old_transport = init_ctl_channel(0);
+ use_old_transport = init_ctl_channel(modname, 1);
if (use_old_transport < 0) {
err("Failed to initialize control channel.\n");
return -1;
@@ -177,7 +235,7 @@ int init_stapio(void)
if (init_oldrelayfs() < 0) {
close_ctl_channel();
return -1;
- }
+ }
} else {
if (init_relayfs() < 0) {
close_ctl_channel();
@@ -192,17 +250,12 @@ int init_stapio(void)
if (target_cmd)
start_cmd();
-
return 0;
}
-/* cleanup_and_exit() closed channels and frees memory
- * then exits with the following status codes:
- * 1 - failed to initialize.
- * 2 - disconnected
- * 3 - initialized
- */
-void cleanup_and_exit (int closed)
+/* cleanup_and_exit() closed channels, frees memory,
+ * removes the module (if necessary) and exits. */
+void cleanup_and_exit(int detach)
{
pid_t err;
static int exiting = 0;
@@ -211,32 +264,34 @@ void cleanup_and_exit (int closed)
return;
exiting = 1;
- setup_main_signals(1);
+ setup_main_signals();
- dbug(1, "CLEANUP AND EXIT closed=%d\n", closed);
+ dbug(1, "detach=%d\n", detach);
/* what about child processes? we will wait for them here. */
err = waitpid(-1, NULL, WNOHANG);
if (err >= 0)
err("\nWaiting for processes to exit\n");
- while(wait(NULL) > 0) ;
+ while (wait(NULL) > 0) ;
if (use_old_transport)
- close_oldrelayfs(closed == 2);
+ close_oldrelayfs(detach);
else
close_relayfs();
dbug(1, "closing control channel\n");
close_ctl_channel();
- if (initialized == 2 && closed == 2) {
- err("\nDisconnecting from systemtap module.\n" \
- "To reconnect, type \"staprun -A %s\"\n", modname);
- } else if (initialized)
- closed = 3;
- else
- closed = 1;
- exit(closed);
+ if (detach) {
+ err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname);
+ } else {
+ dbug(2, "removing %s\n", modname);
+ if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) {
+ perror(modname);
+ _exit(1);
+ }
+ }
+ _exit(0);
}
/**
@@ -247,90 +302,103 @@ int stp_main_loop(void)
{
ssize_t nb;
void *data;
- int type;
+ uint32_t type;
FILE *ofp = stdout;
char recvbuf[8196];
setvbuf(ofp, (char *)NULL, _IOLBF, 0);
- setup_main_signals(0);
+ setup_main_signals();
dbug(2, "in main loop\n");
send_request(STP_READY, NULL, 0);
- while (1) { /* handle messages from control channel */
+ /* handle messages from control channel */
+ while (1) {
nb = read(control_channel, recvbuf, sizeof(recvbuf));
+ dbug(2, "nb=%d\n", (int)nb);
if (nb <= 0) {
if (errno != EINTR)
_perr("Unexpected EOF in read (nb=%ld)", (long)nb);
continue;
}
-
- type = *(int *)recvbuf;
- data = (void *)(recvbuf + sizeof(int));
- switch (type) {
+ type = *(uint32_t *) recvbuf;
+ data = (void *)(recvbuf + sizeof(uint32_t));
+ nb -= sizeof(uint32_t);
+
+ switch (type) {
#ifdef STP_OLD_TRANSPORT
case STP_REALTIME_DATA:
- {
- ssize_t bw = write(out_fd[0], data, nb - sizeof(int));
- if (bw >= 0 && bw != (nb - (ssize_t)sizeof(int))) {
- nb = nb - bw;
- bw = write(out_fd[0], data, nb - sizeof(int));
+ {
+ ssize_t bw = write(out_fd[0], data, nb);
+ if (bw >= 0 && bw != nb) {
+ nb = nb - bw;
+ bw = write(out_fd[0], data, nb);
+ }
+ if (bw != nb) {
+ _perr("write error (nb=%ld)", (long)nb);
+ cleanup_and_exit(0);
+ }
+ break;
}
- if (bw != (nb - (ssize_t)sizeof(int))) {
- _perr("write error (nb=%ld)", (long)nb);
- cleanup_and_exit(1);
- }
- break;
- }
#endif
case STP_OOB_DATA:
- fputs ((char *)data, stderr);
- break;
- case STP_EXIT:
- {
- /* module asks us to unload it and exit */
- int *closed = (int *)data;
- dbug(2, "got STP_EXIT, closed=%d\n", *closed);
- cleanup_and_exit(*closed);
+ fputs((char *)data, stderr);
break;
- }
- case STP_START:
- {
- struct _stp_msg_start *t = (struct _stp_msg_start *)data;
- dbug(2, "probe_start() returned %d\n", t->res);
- if (t->res < 0) {
- if (target_cmd)
- kill (target_pid, SIGKILL);
- cleanup_and_exit(1);
- } else if (target_cmd)
- kill (target_pid, SIGUSR1);
- break;
- }
+ case STP_EXIT:
+ {
+ /* module asks us to unload it and exit */
+ dbug(2, "got STP_EXIT\n");
+ cleanup_and_exit(0);
+ break;
+ }
+ case STP_START:
+ {
+ struct _stp_msg_start *t = (struct _stp_msg_start *)data;
+ dbug(2, "probe_start() returned %d\n", t->res);
+ if (t->res < 0) {
+ if (target_cmd)
+ kill(target_pid, SIGKILL);
+ cleanup_and_exit(0);
+ } else if (target_cmd)
+ kill(target_pid, SIGUSR1);
+ break;
+ }
case STP_SYSTEM:
- {
- struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data;
- dbug(2, "STP_SYSTEM: %s\n", c->cmd);
- system_cmd(c->cmd);
- break;
- }
+ {
+ struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data;
+ dbug(2, "STP_SYSTEM: %s\n", c->cmd);
+ system_cmd(c->cmd);
+ break;
+ }
case STP_TRANSPORT:
- {
- struct _stp_msg_start ts;
- if (use_old_transport) {
- if (init_oldrelayfs() < 0)
- cleanup_and_exit(1);
- } else {
- if (init_relayfs() < 0)
+ {
+ struct _stp_msg_start ts;
+ if (use_old_transport) {
+ if (init_oldrelayfs() < 0)
+ cleanup_and_exit(0);
+ } else {
+ if (init_relayfs() < 0)
+ cleanup_and_exit(0);
+ }
+ ts.target = target_pid;
+ send_request(STP_START, &ts, sizeof(ts));
+ if (load_only)
cleanup_and_exit(1);
+ break;
+ }
+ case STP_UNWIND:
+ {
+ int len;
+ char *ptr = (char *)data;
+ while (nb > 0) {
+ send_unwind_data(ptr);
+ len = strlen(ptr) + 1;
+ ptr += len;
+ nb -= len;
+ }
+ break;
}
- ts.target = target_pid;
- initialized = 2;
- send_request(STP_START, &ts, sizeof(ts));
- if (load_only)
- cleanup_and_exit(2);
- break;
- }
default:
err("WARNING: ignored message of type %d\n", (type));
}
diff --git a/runtime/staprun/stapio.c b/runtime/staprun/stapio.c
index ee30a1a1..3c8c4f7f 100644
--- a/runtime/staprun/stapio.c
+++ b/runtime/staprun/stapio.c
@@ -27,24 +27,23 @@ char *__name__ = "stapio";
int main(int argc, char **argv)
{
setup_signals();
-
parse_args(argc, argv);
if (buffer_size)
- dbug(1, "Using a buffer of %u bytes.\n", buffer_size);
+ dbug(1, "Using a buffer of %u MB.\n", buffer_size);
if (optind < argc) {
parse_modpath(argv[optind++]);
dbug(2, "modpath=\"%s\", modname=\"%s\"\n", modpath, modname);
}
- if (optind < argc) {
+ if (optind < argc) {
if (attach_mod) {
err("ERROR: Cannot have module options with attach (-A).\n");
usage(argv[0]);
} else {
- unsigned start_idx = 3; /* reserve three slots in modoptions[] */
- while (optind < argc && start_idx+1 < MAXMODOPTIONS)
+ unsigned start_idx = 3; /* reserve three slots in modoptions[] */
+ while (optind < argc && start_idx + 1 < MAXMODOPTIONS)
modoptions[start_idx++] = argv[optind++];
modoptions[start_idx] = NULL;
}
@@ -57,13 +56,7 @@ int main(int argc, char **argv)
if (init_stapio())
exit(1);
-
- initialized = 1;
- if (attach_mod) {
- /* already started */
- initialized++;
- }
-
+
if (stp_main_loop()) {
err("ERROR: Couldn't enter main loop. Exiting.\n");
exit(1);
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index f4e67fdb..0291d01f 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -16,21 +16,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Copyright (C) 2005-2007 Red Hat, Inc.
+ * Copyright (C) 2005-2008 Red Hat, Inc.
*
*/
#include "staprun.h"
-int inserted_module = 0;
-
/* used in dbug, _err and _perr */
char *__name__ = "staprun";
extern long delete_module(const char *, unsigned int);
-static int
-run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
+static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
{
pid_t pid;
int rstatus;
@@ -42,14 +39,13 @@ run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
err("%s ", argv[i]);
i++;
}
- err("\n");
+ err("\n");
}
if ((pid = fork()) < 0) {
_perr("fork");
return -1;
- }
- else if (pid == 0) {
+ } else if (pid == 0) {
/* Make sure we run as the full user. If we're
* switching to a non-root user, this won't allow
* that process to switch back to root (since the
@@ -79,17 +75,6 @@ run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
return -1;
}
-/* Keep the uid and gid settings because we will likely */
-/* conditionally restore "-u" */
-static int run_stapio(char **argv)
-{
- uid_t uid = getuid();
- gid_t gid = getgid();
- argv[0] = PKGLIBDIR "/stapio";
-
- return run_as(uid, gid, argv[0], argv);
-}
-
/*
* Module to be inserted has one or more user-space probes. Make sure
* uprobes is enabled.
@@ -132,8 +117,7 @@ static int enable_uprobes(void)
dbug(2, "Inserting uprobes module from SystemTap runtime.\n");
argv[0] = NULL;
- return insert_module(PKGDATADIR "/runtime/uprobes/uprobes.ko",
- NULL, argv);
+ return insert_module(PKGDATADIR "/runtime/uprobes/uprobes.ko", NULL, argv);
}
static int insert_stap_module(void)
@@ -144,6 +128,66 @@ static int insert_stap_module(void)
return insert_module(modpath, bufsize_option, modoptions);
}
+static int remove_module(const char *name, int verb);
+
+static void remove_all_modules(void)
+{
+ char *base;
+ struct statfs st;
+ struct dirent *d;
+ DIR *moddir;
+
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC)
+ base = "/sys/kernel/debug/systemtap";
+ else
+ base = "/proc/systemtap";
+
+ moddir = opendir(base);
+ if (moddir) {
+ while ((d = readdir(moddir)))
+ if (remove_module(d->d_name, 0) == 0)
+ printf("Module %s removed.\n", d->d_name);
+ closedir(moddir);
+ }
+}
+
+static int remove_module(const char *name, int verb)
+{
+ int ret;
+ dbug(2, "%s\n", name);
+
+ if (strcmp(name, "*") == 0) {
+ remove_all_modules();
+ return 0;
+ }
+
+ /* Call init_ctl_channel() which actually attempts an open()
+ * of the control channel. This is better than using access() because
+ * an open on an already open channel will fail, preventing us from attempting
+ * to remove an in-use module.
+ */
+ if (init_ctl_channel(name, 0) < 0) {
+ if (verb)
+ err("Error accessing systemtap module %s: %s\n", name, strerror(errno));
+ return 1;
+ }
+ close_ctl_channel();
+
+ dbug(2, "removing module %s\n", name);
+
+ /* Don't remove module when priority is elevated. */
+ if (setpriority(PRIO_PROCESS, 0, 0) < 0)
+ _perr("setpriority");
+
+ ret = do_cap(CAP_SYS_MODULE, delete_module, name, 0);
+ if (ret != 0) {
+ err("Error removing module '%s': %s.\n", name, strerror(errno));
+ return 1;
+ }
+
+ dbug(1, "Module %s removed.\n", name);
+ return 0;
+}
int init_staprun(void)
{
@@ -154,71 +198,28 @@ int init_staprun(void)
/* We're done with CAP_SYS_ADMIN. */
drop_cap(CAP_SYS_ADMIN);
-
- if (!attach_mod) {
+
+ if (delete_mod)
+ exit(remove_module(modname, 1));
+ else if (!attach_mod) {
if (need_uprobes && enable_uprobes() != 0)
return -1;
if (insert_stap_module() < 0)
return -1;
- else
- inserted_module = 1;
}
-
return 0;
}
-
-static void cleanup(int rc)
-{
- /* Only cleanup once. */
- static int done = 0;
- if (done == 0)
- done = 1;
- else
- return;
-
- dbug(2, "rc=%d, inserted_module=%d\n", rc, inserted_module);
-
- if (setpriority (PRIO_PROCESS, 0, 0) < 0)
- _perr("setpriority");
-
- stop_symbol_thread();
-
- /* rc == 2 means disconnected */
- if (rc == 2)
- return;
-
- /* If we inserted the module and did not get rc==2, then */
- /* we really want to remove it. */
- if (inserted_module || rc == 3) {
- long ret;
- dbug(2, "removing module %s\n", modname);
- ret = do_cap(CAP_SYS_MODULE, delete_module, modname, 0);
- if (ret != 0)
- err("Error removing module '%s': %s\n", modname, moderror(errno));
- }
-}
-
-static void exit_cleanup(void)
-{
- dbug(2, "something exited...\n");
- cleanup(1);
-}
int main(int argc, char **argv)
{
int rc;
- if (atexit(exit_cleanup)) {
- _perr("cannot set exit function");
- exit(1);
- }
-
- /* NB: Don't do the geteuid()!=0 check here, since we want to
- test command-line error-handling while running non-root. */
+ /* NB: Don't do the geteuid()!=0 check here, since we want to
+ test command-line error-handling while running non-root. */
/* Get rid of a few standard environment variables (which */
/* might cause us to do unintended things). */
rc = unsetenv("IFS") || unsetenv("CDPATH") || unsetenv("ENV")
- || unsetenv("BASH_ENV");
+ || unsetenv("BASH_ENV");
if (rc) {
_perr("unsetenv failed");
exit(-1);
@@ -229,20 +230,20 @@ int main(int argc, char **argv)
parse_args(argc, argv);
if (buffer_size)
- dbug(2, "Using a buffer of %u bytes.\n", buffer_size);
+ dbug(2, "Using a buffer of %u MB.\n", buffer_size);
if (optind < argc) {
parse_modpath(argv[optind++]);
dbug(2, "modpath=\"%s\", modname=\"%s\"\n", modpath, modname);
}
- if (optind < argc) {
+ if (optind < argc) {
if (attach_mod) {
err("ERROR: Cannot have module options with attach (-A).\n");
usage(argv[0]);
} else {
unsigned start_idx = 0;
- while (optind < argc && start_idx+1 < MAXMODOPTIONS)
+ while (optind < argc && start_idx + 1 < MAXMODOPTIONS)
modoptions[start_idx++] = argv[optind++];
modoptions[start_idx] = NULL;
}
@@ -254,14 +255,13 @@ int main(int argc, char **argv)
}
if (geteuid() != 0) {
- err("ERROR: The effective user ID of staprun must be set to the root user.\n"
- " Check permissions on staprun and ensure it is a setuid root program.\n");
+ err("ERROR: The effective user ID of staprun must be set to the root user.\n"
+ " Check permissions on staprun and ensure it is a setuid root program.\n");
exit(1);
}
- if (!init_cap())
- exit(1);
-
+ init_cap();
+
if (check_permissions() != 1)
usage(argv[0]);
@@ -277,11 +277,14 @@ int main(int argc, char **argv)
if (init_staprun())
exit(1);
- setup_staprun_signals();
- start_symbol_thread();
-
- rc = run_stapio(argv);
- cleanup(rc);
-
+ argv[0] = PKGLIBDIR "/stapio";
+ if (execv(argv[0], argv) < 0) {
+ perror(argv[0]);
+ goto err;
+ }
return 0;
+
+err:
+ remove_module(modname, 1);
+ return 1;
}
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 1128fb4c..60bab391 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -103,8 +103,6 @@ extern char *__name__;
#define STP_OLD_TRANSPORT
#include "../transport/transport_msgs.h"
-extern int use_old_transport;
-
#define RELAYFS_MAGIC 0xF0B4A981
#define DEBUGFS_MAGIC 0x64626720
#define DEBUGFSDIR "/sys/kernel/debug"
@@ -118,9 +116,8 @@ int init_stapio(void);
int stp_main_loop(void);
int send_request(int type, void *data, int len);
void cleanup_and_exit (int);
-int do_module(void *);
-int do_kernel_symbols(void);
-int init_ctl_channel(int);
+void send_unwind_data(const char *name);
+int init_ctl_channel(const char *name, int verb);
void close_ctl_channel(void);
int init_relayfs(void);
void close_relayfs(void);
@@ -129,7 +126,7 @@ void close_oldrelayfs(int);
void setup_signals(void);
/* cap.c */
void print_cap(char *text);
-int init_cap(void);
+void init_cap(void);
void add_cap(cap_value_t cap);
void del_cap(cap_value_t cap);
void drop_cap(cap_value_t cap);
@@ -169,6 +166,7 @@ extern int target_pid;
extern char *target_cmd;
extern char *outfile_name;
extern int attach_mod;
+extern int delete_mod;
extern int load_only;
extern int need_uprobes;
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
index 34e12c25..c1cb92b7 100644
--- a/runtime/staprun/staprun_funcs.c
+++ b/runtime/staprun/staprun_funcs.c
@@ -16,18 +16,6 @@
#include <grp.h>
#include <pwd.h>
-void setup_staprun_signals(void)
-{
- struct sigaction a;
- memset(&a, 0, sizeof(a));
- sigfillset(&a.sa_mask);
- a.sa_handler = SIG_IGN;
- sigaction(SIGINT, &a, NULL);
- sigaction(SIGTERM, &a, NULL);
- sigaction(SIGHUP, &a, NULL);
- sigaction(SIGQUIT, &a, NULL);
-}
-
extern long init_module(void *, unsigned long, const char *);
/* Module errors get translated. */
@@ -401,95 +389,3 @@ int check_permissions(void)
* is in that directory. */
return check_path();
}
-
-pthread_t symbol_thread_id = (pthread_t)0;
-int kernel_ptr_size = 0;
-
-/* Symbol handling thread */
-void *handle_symbols(void __attribute__((unused)) *arg)
-{
- ssize_t nb;
- void *data;
- int32_t type;
- char recvbuf[8192];
-
- dbug(2, "waiting for symbol requests\n");
-
- /* handle messages from control channel */
- while (1) {
- nb = read(control_channel, recvbuf, sizeof(recvbuf));
- if (nb <= 0) {
- if (errno != EINTR)
- _perr("Unexpected EOF in read (nb=%ld)", (long)nb);
- continue;
- }
-
- type = *(int32_t *)recvbuf;
- data = (void *)(recvbuf + sizeof(int32_t));
-
- switch (type) {
- case STP_MODULE:
- {
- dbug(2, "STP_MODULES request received\n");
- if (do_module(data) < 0)
- goto done;
- break;
- }
- case STP_SYMBOLS:
- {
- struct _stp_msg_symbol *req = (struct _stp_msg_symbol *)data;
- dbug(2, "STP_SYMBOLS request received\n");
- if (req->endian != 0x1234) {
- err("ERROR: staprun is compiled with different endianess than the kernel!\n");
- goto done;
- }
- kernel_ptr_size = req->ptr_size;
- if (kernel_ptr_size != 4 && kernel_ptr_size != 8) {
- err("ERROR: invalid kernel pointer size %d\n", kernel_ptr_size);
- goto done;
- }
- if (do_kernel_symbols() < 0)
- goto done;
- break;
- }
- default:
- err("WARNING: ignored message of type %d\n", (type));
- }
- }
-
-done:
- /* signal stapio we're done */
- kill(0, SIGINT);
-
- 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
deleted file mode 100644
index c7362d9e..00000000
--- a/runtime/staprun/symbols.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/* -*- linux-c -*-
- * Symbols and modules functions for staprun.
- *
- * Copyright (C) 2006-2008 Red Hat Inc.
- *
- * This file is part of systemtap, and is free software. You can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License (GPL); either version 2, or (at your option) any
- * later version.
- */
-
-#include "staprun.h"
-
-/* send symbol data */
-static int send_data(int32_t type, void *data, int len)
-{
- if (write(control_channel, &type, 4) <= 0)
- return -1;
- return write(control_channel, data, len);
-}
-
-
-/* Get the sections for a module. Put them in the supplied buffer */
-/* in the following order: */
-/* [struct _stp_msg_module][struct _stp_symbol sections ...][string data][unwind data] */
-/* Return the total length of all the data. */
-
-#define SECDIR "/sys/module/%s/sections"
-static int get_sections(char *name, char *data_start, int datalen)
-{
- char dir[STP_MODULE_NAME_LEN + sizeof(SECDIR)];
- char filename[STP_MODULE_NAME_LEN + 256];
- char buf[32], strdata_start[32768];
- char *strdata=strdata_start, *data=data_start;
- int fd, len, res, unwind_data_len=0;
- struct _stp_msg_module *mod = (struct _stp_msg_module *)data_start;
-
- struct dirent *d;
- DIR *secdir;
- void *sec;
- int struct_symbol_size = kernel_ptr_size == 8 ? sizeof(struct _stp_symbol64) : sizeof(struct _stp_symbol32);
- uint64_t sec_addr;
-
- /* start of data is a struct _stp_msg_module */
- data += sizeof(struct _stp_msg_module);
-
- res = snprintf(dir, sizeof(dir), SECDIR, name);
- if (res >= (int)sizeof(dir)) {
- _err("Couldn't fit module \"%s\" into dir buffer.\n" \
- "This should never happen. Please file a bug report.\n", name);
- return -1;
- }
-
- if ((secdir = opendir(dir)) == NULL)
- return 0;
-
- /* Initialize mod. */
- memset(mod, 0, sizeof(struct _stp_msg_module));
-
- /* Copy name in and check for overflow. */
- strncpy(mod->name, name, STP_MODULE_NAME_LEN);
- if (mod->name[STP_MODULE_NAME_LEN - 1] != '\0') {
- _err("Couldn't fit module \"%s\" into mod->name buffer.\n" \
- "This should never happen. Please file a bug report.\n", name);
- return -1;
- }
-
- /* FIXME: optionally fill in unwind data here */
- mod->unwind_len = unwind_data_len;
-
- while ((d = readdir(secdir))) {
- char *secname = d->d_name;
-
- /* Copy filename in and check for overflow. */
- res = snprintf(filename, sizeof(filename), "/sys/module/%s/sections/%s", name, secname);
- if (res >= (int)sizeof(filename)) {
- _err("Couldn't fit secname \"%s\" into filename buffer.\n" \
- "This should never happen. Please file a bug report.\n", secname);
- closedir(secdir);
- return -1;
- }
-
- /* filter out some non-useful stuff */
- if (!strncmp(secname,"__",2)
- || !strcmp(secname,".")
- || !strcmp(secname,"..")
- || !strcmp(secname,".module_sig")
- || !strcmp(secname,".modinfo")
- || !strcmp(secname,".strtab")
- || !strcmp(secname,".symtab") ) {
- continue;
- }
- if (!strncmp(secname, ".gnu.linkonce", 13)
- && strcmp(secname, ".gnu.linkonce.this_module"))
- continue;
-
- if ((fd = open(filename,O_RDONLY)) >= 0) {
- if (read(fd, buf, 32) > 0) {
- /* create next section */
- sec = data;
- if (data - data_start + struct_symbol_size > datalen)
- goto err1;
- data += struct_symbol_size;
-
- sec_addr = (uint64_t)strtoull(buf,NULL,16);
- if (kernel_ptr_size == 8) {
- ((struct _stp_symbol64 *)sec)->addr = sec_addr;
- ((struct _stp_symbol64 *)sec)->symbol = (uint64_t)(strdata - strdata_start);
- } else {
- ((struct _stp_symbol32 *)sec)->addr = (uint32_t)sec_addr;
- ((struct _stp_symbol32 *)sec)->symbol = (uint32_t)(strdata - strdata_start);
- }
- mod->num_sections++;
-
- /* now create string data for the
- * section (checking for overflow) */
- if ((strdata - strdata_start + strlen(strdata))
- >= sizeof(strdata_start))
- goto err1;
- strcpy(strdata, secname);
- strdata += strlen(secname) + 1;
-
- /* These sections are used a lot so keep the values handy */
- if (!strcmp(secname, ".data") || !strncmp(secname, ".rodata", 7)) {
- if (mod->data == 0 || sec_addr < mod->data)
- mod->data = sec_addr;
- }
- if (!strcmp(secname, ".text"))
- mod->text = sec_addr;
- if (!strcmp(secname, ".gnu.linkonce.this_module"))
- mod->module = sec_addr;
- }
- close(fd);
- }
- }
- closedir(secdir);
-
- /* consolidate buffers */
- len = strdata - strdata_start;
- if ((len + data - data_start) > datalen)
- goto err0;
- strdata = strdata_start;
- while (len--)
- *data++ = *strdata++;
-
-#if 0
- if (unwind_data_len) {
- if ((unwind_data_len + data - data_start) > datalen)
- goto err0;
- memcpy(data, unwind_data, unwind_data_len);
- data += unwind_data_len;
- }
-#endif
- return data - data_start;
-
-err1:
- close(fd);
- closedir(secdir);
-err0:
- /* if this happens, something went seriously wrong. */
- _err("Unexpected error. Overflowed buffers.\n");
- return -1;
-}
-#undef SECDIR
-
-/*
- * For modules, we send the name, section names, and offsets
- */
-static int send_module (char *mname)
-{
- char data[65536];
- int len;
- len = get_sections(mname, data, sizeof(data));
- if (len > 0) {
- if (send_data(STP_MODULE, data, len) < 0) {
- _err("Loading of module %s failed. Exiting...\n", mname);
- return -1;
- }
- }
- return len;
-}
-
-/*
- * Send either all modules, or a specific one.
- * Returns:
- * >=0 : OK
- * -1 : serious error (exit)
- */
-int do_module (void *data)
-{
- struct _stp_msg_module *mod = (struct _stp_msg_module *)data;
-
- if (mod->name[0] == 0) {
- struct dirent *d;
- DIR *moddir = opendir("/sys/module");
- if (moddir) {
- while ((d = readdir(moddir)))
- if (send_module(d->d_name) < 0) {
- closedir(moddir);
- return -1;
- }
- closedir(moddir);
- }
- send_request(STP_MODULE, data, 1);
- return 0;
- }
-
- return send_module(mod->name);
-}
-
-#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.
- */
-int do_kernel_symbols(void)
-{
- FILE *kallsyms=NULL;
- char *name, *mod, *dataptr, *datamax, type, *data_base=NULL;
- unsigned long long addr;
- void *syms = NULL;
- int ret, num_syms, i = 0, struct_symbol_size;
- int max_syms= MAX_SYMBOLS, data_basesize = MAX_SYMBOLS*32;
-
- if (kernel_ptr_size == 8)
- struct_symbol_size = sizeof(struct _stp_symbol64);
- else
- struct_symbol_size = sizeof(struct _stp_symbol32);
-
- syms = malloc(max_syms * struct_symbol_size);
- data_base = malloc(data_basesize);
- if (data_base == NULL || syms == NULL) {
- _err("Failed to allocate memory for symbols\n");
- goto err;
- }
- dataptr = data_base;
- datamax = data_base + data_basesize;
-
- kallsyms = fopen ("/proc/kallsyms", "r");
- if (!kallsyms) {
- _perr("Fatal error: Unable to open /proc/kallsyms");
- goto err;
- }
-
- /* put empty string in data */
- *dataptr++ = 0;
-
- while ((ret = fscanf(kallsyms, "%llx %c %as [%as", &addr, &type, &name, &mod))>0
- && dataptr < datamax) {
- if (ret < 3)
- continue;
- if (ret > 3) {
- /* ignore modules */
- free(name);
- free(mod);
- /* modules are loaded above the kernel, so if we */
- /* are getting modules, then we're done. */
- break;
- }
-
- if (type == 't' || type == 'T' || type == 'A') {
- if (kernel_ptr_size == 8) {
- ((struct _stp_symbol64 *)syms)[i].addr = (uint64_t)addr;
- ((struct _stp_symbol64 *)syms)[i].symbol = (uint64_t)(dataptr - data_base);
- } else {
- ((struct _stp_symbol32 *)syms)[i].addr = (uint32_t)addr;
- ((struct _stp_symbol32 *)syms)[i].symbol = (uint32_t)(dataptr - data_base);
- }
- if (dataptr >= datamax - strlen(name)) {
- char *db;
- data_basesize *= 2;
- db = realloc(data_base, data_basesize);
- if (db == NULL) {
- _err("Could not allocate enough space for symbols.\n");
- goto err;
- }
- dataptr = db + (dataptr - data_base);
- datamax = db + data_basesize;
- data_base = db;
- }
- strcpy(dataptr, name);
- dataptr += strlen(name) + 1;
- free(name);
- i++;
- if (i >= max_syms) {
- max_syms *= 2;
- syms = realloc(syms, max_syms*struct_symbol_size);
- if (syms == NULL) {
- _err("Could not allocate enough space for symbols.\n");
- goto err;
- }
- }
- }
- }
- num_syms = i;
- if (num_syms <= 0)
- goto err;
-
-
- /* send header */
- struct _stp_msg_symbol_hdr smsh;
- smsh.num_syms = num_syms;
- smsh.sym_size = (uint32_t)(dataptr - data_base);
- smsh.unwind_size = (uint32_t)0;
- if (send_request(STP_SYMBOLS, &smsh, sizeof(smsh)) <= 0)
- goto err;
-
- /* send syms */
- if (send_data(STP_SYMBOLS, syms, num_syms*struct_symbol_size) < 0)
- goto err;
-
- /* send data */
- if (send_data(STP_SYMBOLS, data_base, dataptr-data_base) < 0)
- goto err;
-
- free(data_base);
- free(syms);
- fclose(kallsyms);
- return 0;
-
-err:
- if (data_base)
- free(data_base);
- if (syms)
- free(syms);
- if (kallsyms)
- fclose(kallsyms);
-
- _err("Loading of symbols failed. Exiting...\n");
- return -1;
-}
diff --git a/runtime/staprun/unwind_data.c b/runtime/staprun/unwind_data.c
new file mode 100644
index 00000000..ed27cc20
--- /dev/null
+++ b/runtime/staprun/unwind_data.c
@@ -0,0 +1,97 @@
+/* -*- linux-c -*-
+ * Unwind data functions for staprun.
+ *
+ * Copyright (C) 2008 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#include "staprun.h"
+#include <elfutils/libdwfl.h>
+#include <dwarf.h>
+
+static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug";
+static char *debuginfo_path = debuginfo_path_arr;
+static const Dwfl_Callbacks kernel_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+ .find_elf = dwfl_linux_kernel_find_elf,
+ .section_address = dwfl_linux_kernel_module_section_address,
+};
+
+void *get_module_unwind_data(Dwfl * dwfl, const char *name, int *len)
+{
+ Dwarf_Addr bias = 0;
+ Dwarf *dw;
+ GElf_Ehdr *ehdr, ehdr_mem;
+ GElf_Shdr *shdr, shdr_mem;
+ Elf_Scn *scn = NULL;
+ Elf_Data *data = NULL;
+
+ Dwfl_Module *mod = dwfl_report_module(dwfl, name, 0, 0);
+ dwfl_report_end(dwfl, NULL, NULL);
+ dw = dwfl_module_getdwarf(mod, &bias);
+ Elf *elf = dwarf_getelf(dw);
+ ehdr = gelf_getehdr(elf, &ehdr_mem);
+ while ((scn = elf_nextscn(elf, scn))) {
+ shdr = gelf_getshdr(scn, &shdr_mem);
+ if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), ".debug_frame") == 0) {
+ data = elf_rawdata(scn, NULL);
+ break;
+ }
+ }
+
+ if (data == NULL) {
+ *len = 0;
+ dbug(2, "module %s returns NULL\n", name);
+ return NULL;
+ }
+ dbug(2, "module %s returns %d\n", name, (int)data->d_size);
+ *len = data->d_size;
+ return data->d_buf;
+}
+
+void send_unwind_data(const char *name)
+{
+ struct _stp_msg_unwind *un;
+ int unwind_data_len = 0;
+ void *unwind_data = NULL;
+ char *buf;
+
+ dbug(2, "module %s\n", name);
+ if (strcmp(name, "*")) {
+ Dwfl *dwfl = dwfl_begin(&kernel_callbacks);
+
+ if (name[0] == 0)
+ unwind_data = get_module_unwind_data(dwfl, "kernel", &unwind_data_len);
+ else
+ unwind_data = get_module_unwind_data(dwfl, name, &unwind_data_len);
+
+ /* yuck */
+ buf = (char *)malloc(unwind_data_len + sizeof(*un) + sizeof(uint32_t));
+ if (!buf) {
+ err("malloc failed\n");
+ return;
+ }
+ memcpy(buf + sizeof(*un) + sizeof(uint32_t), unwind_data, unwind_data_len);
+ dwfl_end(dwfl);
+ } else {
+ buf = (char *)malloc(sizeof(*un) + sizeof(uint32_t));
+ if (!buf) {
+ err("malloc failed\n");
+ return;
+ }
+ }
+
+ un = (struct _stp_msg_unwind *)(buf + sizeof(uint32_t));
+ strncpy(un->name, name, sizeof(un->name));
+ un->unwind_len = unwind_data_len;
+ *(uint32_t *) buf = STP_UNWIND;
+
+ /* send unwind data */
+ if (write(control_channel, buf, unwind_data_len + sizeof(*un) + sizeof(uint32_t)) <= 0)
+ err("write failed\n");
+}