summaryrefslogtreecommitdiffstats
path: root/runtime/stpd
diff options
context:
space:
mode:
authorhunt <hunt>2006-11-02 18:37:00 +0000
committerhunt <hunt>2006-11-02 18:37:00 +0000
commitf1bad60c76d79f01a87e4128df266bf4252a71e0 (patch)
tree5114f087d844e702253a439efbcc36e310268a4b /runtime/stpd
parent202e1828643725d7bebef76c48cbaa28c463cee3 (diff)
downloadsystemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.gz
systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.xz
systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.zip
New dynamic module and symbol handling code.
Diffstat (limited to 'runtime/stpd')
-rw-r--r--runtime/stpd/ChangeLog13
-rw-r--r--runtime/stpd/Makefile14
-rw-r--r--runtime/stpd/librelay.c88
-rw-r--r--runtime/stpd/librelay.h16
-rw-r--r--runtime/stpd/symbols.c226
5 files changed, 311 insertions, 46 deletions
diff --git a/runtime/stpd/ChangeLog b/runtime/stpd/ChangeLog
index 964f9018..82f3c59c 100644
--- a/runtime/stpd/ChangeLog
+++ b/runtime/stpd/ChangeLog
@@ -1,3 +1,16 @@
+2006-11-02 Martin Hunt <hunt@redhat.com>
+
+ * symbols.c: New file. Sends symbol and module information to
+ the systemtap module.
+
+ * librelay.c (stp_main_loop): Add STP_MODULE and STP_SYMBOLS
+ message handling.
+
+ * librelay.h: Add some new function prototypes.
+
+ * Makefile (CFLAGS): Set to be the same as for building modules.
+ Added symbols.c to sources.
+
2006-10-10 Tom Zanussi <zanussi@us.ibm.com>
* librelay.c (merge_output): Add check for min when writing
diff --git a/runtime/stpd/Makefile b/runtime/stpd/Makefile
index c6d08326..48613a0a 100644
--- a/runtime/stpd/Makefile
+++ b/runtime/stpd/Makefile
@@ -1,16 +1,18 @@
+CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -fexceptions -Wall -Werror -Wshadow -Wunused
+
all: staprun stp_merge stp_dump
-staprun: stpd.c librelay.c ../transport/transport_msgs.h librelay.h
- gcc -Wall -O3 -o staprun stpd.c librelay.c -lpthread
+staprun: stpd.c librelay.c symbols.c ../transport/transport_msgs.h librelay.h
+ gcc -O3 $(CFLAGS) -o staprun stpd.c librelay.c symbols.c -lpthread
stp_merge: stp_merge.c
- gcc -Wall -O3 -o stp_merge stp_merge.c
+ gcc -O3 $(CFLAGS) -o stp_merge stp_merge.c
stp_dump: stp_dump.c
- gcc -Wall -O3 -o stp_dump stp_dump.c
+ gcc -O3 $(CFLAGS) -o stp_dump stp_dump.c
-debug: stpd.c librelay.c ../transport/transport_msgs.h librelay.h
- gcc -Wall -g -D DEBUG -o staprun stpd.c librelay.c -lpthread
+debug: stpd.c librelay.c symbols.c ../transport/transport_msgs.h librelay.h
+ gcc -g -D DEBUG $(CFLAGS) -o staprun stpd.c librelay.c symbols.c -lpthread
clean:
/bin/rm -f staprun stp_merge *.o *~
diff --git a/runtime/stpd/librelay.c b/runtime/stpd/librelay.c
index 0a5040c2..259c2cc7 100644
--- a/runtime/stpd/librelay.c
+++ b/runtime/stpd/librelay.c
@@ -19,7 +19,6 @@
* Copyright (C) Red Hat Inc, 2005, 2006
*
*/
-
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -43,6 +42,7 @@
#include <stdint.h>
#include "librelay.h"
+
/* stp_check script */
#ifdef PKGLIBDIR
char *stp_check=PKGLIBDIR "/stp_check";
@@ -87,7 +87,7 @@ static char *relay_buffer[NR_CPUS];
static pthread_t reader[NR_CPUS];
/* control channel */
-static int control_channel;
+int control_channel;
/* flags */
extern int print_only, quiet, verbose;
@@ -110,6 +110,8 @@ static struct buf_status
unsigned max_backlog; /* max # sub-buffers ready at one time */
} status[NR_CPUS];
+
+
/**
* streaming - is the current transport mode streaming or not?
*
@@ -140,7 +142,6 @@ int send_request(int type, void *data, int len)
}
-
/**
* summarize - print a summary if applicable
*/
@@ -486,9 +487,6 @@ void system_cmd(char *cmd)
}
}
-#include <sys/wait.h>
-static void cleanup_and_exit (int);
-
/**
* init_stp - initialize the app
* @print_summary: boolean, print summary or not at end of run
@@ -559,7 +557,7 @@ int init_stp(int print_summary)
}
return 0;
-do_rmmod:
+ do_rmmod:
snprintf(buf, sizeof(buf), "/sbin/rmmod -w %s", modname);
if (system(buf))
fprintf(stderr, "ERROR: couldn't rmmod probe module %s.\n", modname);
@@ -654,7 +652,7 @@ static int merge_output(void)
return 0;
}
-static void cleanup_and_exit (int closed)
+void cleanup_and_exit (int closed)
{
char tmpbuf[128];
pid_t err;
@@ -733,7 +731,6 @@ static char recvbuf[8192];
int stp_main_loop(void)
{
int nb, rc;
- struct transport_start ts;
void *data;
int type;
FILE *ofp = stdout;
@@ -767,9 +764,41 @@ int stp_main_loop(void)
}
switch (type) {
+ case STP_REALTIME_DATA:
+ fwrite_unlocked(data, nb - sizeof(int), 1, ofp);
+ break;
+ case STP_OOB_DATA:
+ fputs ((char *)data, stderr);
+ break;
+ case STP_EXIT:
+ {
+ /* module asks us to unload it and exit */
+ int *closed = (int *)data;
+ cleanup_and_exit(*closed);
+ break;
+ }
+ case STP_START:
+ {
+ struct transport_start *t = (struct transport_start *)data;
+ dbug("probe_start() returned %d\n", t->pid);
+ if (t->pid < 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 cmd_info *c = (struct cmd_info *)data;
+ system_cmd(c->cmd);
+ break;
+ }
case STP_TRANSPORT_INFO:
{
- struct transport_info *info = (struct transport_info *)data;
+ struct transport_info *info = (struct transport_info *)data;
+ struct transport_start ts;
transport_mode = info->transport_mode;
params.subbuf_size = info->subbuf_size;
params.n_subbufs = info->n_subbufs;
@@ -804,35 +833,22 @@ int stp_main_loop(void)
send_request(STP_START, &ts, sizeof(ts));
break;
}
- case STP_REALTIME_DATA:
- fwrite_unlocked(data, nb - sizeof(int), 1, ofp);
- break;
- case STP_OOB_DATA:
- fputs ((char *)data, stderr);
- break;
- case STP_EXIT:
+ case STP_MODULE:
{
- /* module asks us to unload it and exit */
- int *closed = (int *)data;
- cleanup_and_exit(*closed);
- break;
- }
- case STP_START:
- {
- struct transport_start *t = (struct transport_start *)data;
- dbug("probe_start() returned %d\n", t->pid);
- if (t->pid < 0) {
- if (target_cmd)
- kill (target_pid, SIGKILL);
- cleanup_and_exit(0);
- } else if (target_cmd)
- kill (target_pid, SIGUSR1);
+ struct transport_start ts;
+ if (do_module(data)) {
+ ts.pid = getpid();
+ send_request(STP_START, &ts, sizeof(ts));
+ }
break;
- }
- case STP_SYSTEM:
+ }
+ case STP_SYMBOLS:
{
- struct cmd_info *c = (struct cmd_info *)data;
- system_cmd(c->cmd);
+ struct transport_start ts;
+ dbug("STP_SYMBOLS request received\n");
+ do_kernel_symbols();
+ ts.pid = getpid();
+ send_request(STP_START, &ts, sizeof(ts));
break;
}
default:
diff --git a/runtime/stpd/librelay.h b/runtime/stpd/librelay.h
index 0a6a1920..38d62369 100644
--- a/runtime/stpd/librelay.h
+++ b/runtime/stpd/librelay.h
@@ -7,8 +7,16 @@
#endif /* DEBUG */
/*
- * stp external API functions
+ * functions
*/
-extern int init_stp(int print_summary);
-extern int stp_main_loop(void);
-extern int send_request(int type, void *data, int len);
+int init_stp(int print_summary);
+int stp_main_loop(void);
+int send_request(int type, void *data, int len);
+void cleanup_and_exit (int);
+int do_module(void *);
+void do_kernel_symbols(void);
+
+/*
+ * variables
+ */
+extern int control_channel;
diff --git a/runtime/stpd/symbols.c b/runtime/stpd/symbols.c
new file mode 100644
index 00000000..09724ea2
--- /dev/null
+++ b/runtime/stpd/symbols.c
@@ -0,0 +1,226 @@
+/* -*- linux-c -*-
+ * Symbols and modules functions for staprun.
+ *
+ * Copyright (C) 2006 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "librelay.h"
+#include "../sym.h"
+
+static int send_data(void *data, int len)
+{
+ return write(control_channel, data, len);
+}
+
+/* Get the sections for a module. Put them in the supplied buffer */
+/* in the following order: */
+/* [struct _stp_module][struct _stp_symbol sections ...][string data] */
+/* Return the total length of all the data. */
+static int get_sections(char *name, char *data_start, int datalen)
+{
+ char dir[64], filename[64], buf[32], strdata_start[2048];
+ char *strdata=strdata_start, *data=data_start;
+ int fd, len;
+ struct _stp_module *mod = (struct _stp_module *)data_start;
+ struct dirent *d;
+ DIR *secdir;
+ struct _stp_symbol *sec;
+
+ /* start of data is a struct _stp_module */
+ data += sizeof(struct _stp_module);
+
+ sprintf(dir,"/sys/module/%s/sections", name);
+ if ((secdir = opendir(dir)) == NULL)
+ return 0;
+
+ memset(mod, 0, sizeof(struct _stp_module));
+ strncpy(mod->name, name, STP_MODULE_NAME_LEN);
+
+ while ((d = readdir(secdir))) {
+ char *secname = d->d_name;
+ sprintf(filename,"/sys/module/%s/sections/%s", name,secname);
+ if ((fd = open(filename,O_RDONLY)) >= 0) {
+ if (read(fd, buf, 32) > 0) {
+ /* filter out some non-useful stuff */
+ if (!strncmp(secname,"__",2)
+ || !strcmp(secname,".module_sig")
+ || !strcmp(secname,".modinfo")
+ || !strcmp(secname,".strtab")
+ || !strcmp(secname,".symtab") ) {
+ close(fd);
+ continue;
+ }
+ /* create next section */
+ sec = (struct _stp_symbol *)data;
+ data += sizeof(struct _stp_symbol);
+ sec->addr = strtoul(buf,NULL,16);
+ sec->symbol = (char *)(strdata - strdata_start);
+ mod->num_sections++;
+
+ /* now create string data for the section */
+ strcpy(strdata, secname);
+ strdata += strlen(secname) + 1;
+
+ /* These sections are used a lot so keep the values handy */
+ if (!strcmp(secname, ".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) {
+ fprintf(stderr, "ERROR: overflowed buffers in get_sections. Size needed = %d\n",
+ (int)(len + data - data_start));
+ cleanup_and_exit(0);
+ }
+ strdata = strdata_start;
+ while (len--)
+ *data++ = *strdata++;
+
+ return data - data_start;
+}
+
+
+void send_module (char *modname)
+{
+ char data[8192];
+ int len = get_sections(modname, data, sizeof(data));
+ if (len)
+ send_request(STP_MODULE, data, len);
+}
+
+int do_module (void *data)
+{
+ struct _stp_module *mod = (struct _stp_module *)data;
+
+ if (mod->name[0] == 0) {
+ struct dirent *d;
+ DIR *moddir = opendir("/sys/module");
+ if (moddir) {
+ while ((d = readdir(moddir)))
+ send_module(d->d_name);
+ closedir(moddir);
+ }
+ return 1;
+ }
+
+ send_module(mod->name);
+ return 0;
+}
+
+static int compar(const void *p1, const void *p2)
+{
+ struct _stp_symbol *s1 = (struct _stp_symbol *)p1;
+ struct _stp_symbol *s2 = (struct _stp_symbol *)p2;
+ if (s1->addr == s2->addr) return 0;
+ if (s1->addr < s2->addr) return -1;
+ return 1;
+}
+
+#define MAX_SYMBOLS 32768
+
+void do_kernel_symbols(void)
+{
+ FILE *kallsyms;
+ char *sym_base, *data_base;
+ char buf[128], *ptr, *name, *data, *dataptr, *datamax, type;
+ unsigned long addr;
+ struct _stp_symbol *syms;
+ int num_syms, i = 0;
+
+ sym_base = malloc(MAX_SYMBOLS*sizeof(struct _stp_symbol)+sizeof(int));
+ data_base = malloc(MAX_SYMBOLS*32);
+ if (data_base == NULL || sym_base == NULL) {
+ fprintf(stderr,"Failed to allocate memory for symbols\n");
+ cleanup_and_exit(0);
+ }
+ *(int *)data_base = STP_SYMBOLS;
+ dataptr = data = data_base + sizeof(int);
+ datamax = dataptr + MAX_SYMBOLS*32 - sizeof(int);
+
+ *(int *)sym_base = STP_SYMBOLS;
+ syms = (struct _stp_symbol *)(sym_base + sizeof(int));
+
+ kallsyms = fopen ("/proc/kallsyms", "r");
+ if (!kallsyms) {
+ perror("Fatal error: Unable to open /proc/kallsyms:");
+ cleanup_and_exit(0);
+ }
+
+ /* put empty string in data */
+ *dataptr++ = 0;
+
+ while (fgets_unlocked(buf, 128, kallsyms) && dataptr < datamax) {
+ addr = strtoul(buf, &ptr, 16);
+ while (isspace(*ptr)) ptr++;
+ type = *ptr++;
+ if (type == 't' || type == 'T' || type == 'A') {
+ while (isspace(*ptr)) ptr++;
+ name = ptr++;
+ while (!isspace(*ptr)) ptr++;
+ *ptr++ = 0;
+ while (*ptr && *ptr != '[') ptr++;
+ if (*ptr)
+ continue; /* it was a module */
+ syms[i].addr = addr;
+ syms[i].symbol = (char *)(dataptr - data);
+ while (*name) *dataptr++ = *name++;
+ *dataptr++ = 0;
+ i++;
+ if (dataptr > datamax - 1000)
+ break;
+ }
+ }
+ num_syms = i;
+ qsort(syms, num_syms, sizeof(struct _stp_symbol), compar);
+
+#if 0
+ for (i=0;i<num_syms;i++) {
+ fprintf(stderr,"%p , \"%s\"\n", (char *)(syms[i].addr),
+ (char *)((long)(syms[i].symbol) + data));
+ }
+#endif
+
+ /* send header */
+ *(int *)buf = num_syms;
+ *(int *)(buf+4) = (unsigned)(dataptr - data);
+ send_request(STP_SYMBOLS, buf, 8);
+
+ /* send syms */
+ send_data(sym_base, num_syms*sizeof(struct _stp_symbol)+sizeof(int));
+
+ /* send data */
+ send_data(data_base, dataptr-data+sizeof(int));
+
+ free(data_base);
+ free(sym_base);
+ fclose(kallsyms);
+
+ if (dataptr >= datamax) {
+ fprintf(stderr,"Error: overflowed symbol data area.\n");
+ cleanup_and_exit(0);
+ }
+}