summaryrefslogtreecommitdiffstats
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
parent202e1828643725d7bebef76c48cbaa28c463cee3 (diff)
downloadsystemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.gz
systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.xz
systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.zip
New dynamic module and symbol handling code.
-rw-r--r--ChangeLog18
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in20
-rw-r--r--main.cxx1
-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
-rw-r--r--runtime/sym.c101
-rw-r--r--runtime/sym.h53
-rw-r--r--runtime/transport/ChangeLog15
-rw-r--r--runtime/transport/procfs.c12
-rw-r--r--runtime/transport/symbols.c420
-rw-r--r--runtime/transport/transport.c45
-rw-r--r--runtime/transport/transport_msgs.h4
-rw-r--r--session.h1
-rw-r--r--tapsets.cxx54
-rw-r--r--translate.cxx13
19 files changed, 973 insertions, 143 deletions
diff --git a/ChangeLog b/ChangeLog
index 597a0e19..f19ce0ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2006-11-02 Martin Hunt <hunt@redhat.com>
+
+ * session.h (struct systemtap_session): Add symtab. This controls
+ if a symbol table is generated and compiled into the module.
+
+ * main.cxx (main): Set session.symtab to false. This could later
+ enabled by a command-line option if necessary.
+
+ * translate.cxx (emit_symbol_data): Don't write a symbol table if
+ session.symtab is false.
+
+ * tapsets.cxx (emit_module_decls): Remove stap_module array and
+ module_relocate.
+ (emit_module_init): Use "_stp_module_relocate".
+
+ * Makefile.am (staprun_SOURCES): Add symbols.c
+ * Makefile.in: Rebuilt.
+
2006-11-02 David Smith <dsmith@redhat.com>
* main.cxx (main): Added '-r' check. If the user changes the
diff --git a/Makefile.am b/Makefile.am
index e810590b..688f27a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,7 @@ install-elfutils:
install-exec-local: install-elfutils
endif
-staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c
+staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c runtime/stpd/symbols.c
staprun_LDADD = -lpthread
pkglibexec_SCRIPTS = stp_check
diff --git a/Makefile.in b/Makefile.in
index 8f1e88c6..25645010 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -98,7 +98,8 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \
stap-hash.$(OBJEXT) stap-mdfour.$(OBJEXT) stap-cache.$(OBJEXT) \
stap-util.$(OBJEXT)
stap_OBJECTS = $(am_stap_OBJECTS)
-am_staprun_OBJECTS = stpd.$(OBJEXT) librelay.$(OBJEXT)
+am_staprun_OBJECTS = stpd.$(OBJEXT) librelay.$(OBJEXT) \
+ symbols.$(OBJEXT)
staprun_OBJECTS = $(am_staprun_OBJECTS)
staprun_DEPENDENCIES =
pkglibexecSCRIPT_INSTALL = $(INSTALL_SCRIPT)
@@ -262,7 +263,7 @@ CLEANFILES = $(am__append_3) $(pkglibexec_SCRIPTS)
@BUILD_ELFUTILS_TRUE@DISTCHECK_CONFIGURE_FLAGS = --with-elfutils=$(elfutils_abs_srcdir)
@BUILD_ELFUTILS_TRUE@BUILT_SOURCES = stamp-elfutils
@BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so
-staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c
+staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c runtime/stpd/symbols.c
staprun_LDADD = -lpthread
pkglibexec_SCRIPTS = stp_check
loc2c_test_SOURCES = loc2c-test.c loc2c.c
@@ -448,6 +449,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-translate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stpd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbols.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -547,6 +549,20 @@ librelay.obj: runtime/stpd/librelay.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o librelay.obj `if test -f 'runtime/stpd/librelay.c'; then $(CYGPATH_W) 'runtime/stpd/librelay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/librelay.c'; fi`
+symbols.o: runtime/stpd/symbols.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT symbols.o -MD -MP -MF "$(DEPDIR)/symbols.Tpo" -c -o symbols.o `test -f 'runtime/stpd/symbols.c' || echo '$(srcdir)/'`runtime/stpd/symbols.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/symbols.Tpo" "$(DEPDIR)/symbols.Po"; else rm -f "$(DEPDIR)/symbols.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stpd/symbols.c' object='symbols.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o symbols.o `test -f 'runtime/stpd/symbols.c' || echo '$(srcdir)/'`runtime/stpd/symbols.c
+
+symbols.obj: runtime/stpd/symbols.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT symbols.obj -MD -MP -MF "$(DEPDIR)/symbols.Tpo" -c -o symbols.obj `if test -f 'runtime/stpd/symbols.c'; then $(CYGPATH_W) 'runtime/stpd/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/symbols.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/symbols.Tpo" "$(DEPDIR)/symbols.Po"; else rm -f "$(DEPDIR)/symbols.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stpd/symbols.c' object='symbols.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o symbols.obj `if test -f 'runtime/stpd/symbols.c'; then $(CYGPATH_W) 'runtime/stpd/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/symbols.c'; fi`
+
.cxx.o:
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
diff --git a/main.cxx b/main.cxx
index 47cedd19..88c55cc2 100644
--- a/main.cxx
+++ b/main.cxx
@@ -203,6 +203,7 @@ main (int argc, char * const argv [])
s.target_pid = 0;
s.merge=true;
s.perfmon=0;
+ s.symtab = false;
s.use_cache = true;
const char* s_p = getenv ("SYSTEMTAP_TAPSET");
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);
+ }
+}
diff --git a/runtime/sym.c b/runtime/sym.c
index c10e89fd..5f2cfc2c 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -20,22 +20,54 @@
* @{
*/
+static unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset) {
+ static struct _stp_module *last = NULL;
+ static struct _stp_symbol *last_sec;
+ unsigned long flags;
+ int i,j;
+
+ STP_LOCK_MODULES;
+ if (! module || _stp_num_modules == 0) {
+ STP_UNLOCK_MODULES;
+ return offset;
+ }
+
+ if (last) {
+ if (!strcmp (module, last->name) && !strcmp (section, last_sec->symbol)) {
+ STP_UNLOCK_MODULES;
+ return offset + last_sec->addr;
+ }
+ }
+
+ /* need to scan all modules */
+ for (i = 1; i < _stp_num_modules; i++) {
+ last = _stp_modules[i];
+ if (strcmp(module, last->name))
+ continue;
+ for (j = 0; j < last->num_sections; j++) {
+ last_sec = &last->sections[j];
+ if (!strcmp (section, last_sec->symbol)) {
+ STP_UNLOCK_MODULES;
+ return offset + last_sec->addr;
+ }
+ }
+ }
+ STP_UNLOCK_MODULES;
+ last = NULL;
+ return 0;
+}
+
/* Lookup the kernel address for this symbol. Returns 0 if not found. */
static unsigned long _stp_kallsyms_lookup_name(const char *name)
{
- struct stap_symbol *s = &stap_symbols[0];
- unsigned num = stap_num_symbols;
-
- /* Warning: Linear search. If this function ends up being used in */
- /* time-critical places, maybe we need to create a new symbol table */
- /* sorted by name. */
+ struct _stp_symbol *s = _stp_modules[0]->symbols;
+ unsigned num = _stp_modules[0]->num_symbols;
while (num--) {
- if ((strcmp(name, s->symbol) == 0) && (strcmp(s->modname,"") == 0))
+ if (strcmp(name, s->symbol) == 0)
return s->addr;
s++;
}
-
return 0;
}
@@ -46,29 +78,51 @@ static const char * _stp_kallsyms_lookup (
char **modname,
char *namebuf)
{
- unsigned begin = 0;
- unsigned end = stap_num_symbols;
- /*const*/ struct stap_symbol* s;
+ struct _stp_module *m;
+ struct _stp_symbol *s;
+ unsigned long flags;
+ unsigned end, begin = 0;
+
+ if (STP_TRYLOCK_MODULES)
+ return NULL;
+
+ end = _stp_num_modules;
- /* binary search on index [begin,end) */
+ if (_stp_num_modules >= 2 && addr > _stp_modules_by_addr[1]->text) {
+ /* binary search on index [begin,end) */
+ do {
+ unsigned mid = (begin + end) / 2;
+ if (addr < _stp_modules_by_addr[mid]->text)
+ end = mid;
+ else
+ begin = mid;
+ } while (begin + 1 < end);
+ /* result index in $begin, guaranteed between [0,_stp_num_modules) */
+ }
+ m = _stp_modules_by_addr[begin];
+ begin = 0;
+ end = m->num_symbols;
+
+ /* binary search for symbols within the module */
do {
unsigned mid = (begin + end) / 2;
- if (addr < stap_symbols[mid].addr)
+ if (addr < m->symbols[mid].addr)
end = mid;
else
begin = mid;
} while (begin + 1 < end);
- /* result index in $begin, guaranteed between [0,stap_num_symbols) */
+ /* result index in $begin */
- s = & stap_symbols [begin];
- if (addr < s->addr)
+ s = &m->symbols[begin];
+ if (addr < s->addr) {
+ STP_UNLOCK_MODULES;
return NULL;
- else {
+ } else {
if (offset) *offset = addr - s->addr;
- if (modname) *modname = (char *) s->modname;
+ if (modname) *modname = m->name;
if (symbolsize) {
- if ((begin + 1) < stap_num_symbols)
- *symbolsize = stap_symbols[begin+1].addr - s->addr;
+ if ((begin + 1) < m->num_symbols)
+ *symbolsize = m->symbols[begin+1].addr - s->addr;
else
*symbolsize = 0;
// NB: This is only a heuristic. Sometimes there are large
@@ -76,11 +130,16 @@ static const char * _stp_kallsyms_lookup (
}
if (namebuf) {
strlcpy (namebuf, s->symbol, KSYM_NAME_LEN+1);
+ STP_UNLOCK_MODULES;
return namebuf;
}
- else
+ else {
+ STP_UNLOCK_MODULES;
return s->symbol;
+ }
}
+ STP_UNLOCK_MODULES;
+ return NULL;
}
/** Write addresses symbolically into a String
diff --git a/runtime/sym.h b/runtime/sym.h
index 6ed08b06..4bbbbbb5 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Red Hat Inc.
+ * Copyright (C) 2005, 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
@@ -10,16 +10,55 @@
#ifndef _STAP_SYMBOLS_H_
#define _STAP_SYMBOLS_H_
+#define STP_MODULE_NAME_LEN 64
-/* A symbol table defined by the translator. */
-struct stap_symbol {
+struct _stp_symbol {
unsigned long addr;
const char *symbol;
- const char *modname;
};
-extern struct stap_symbol stap_symbols [];
-extern unsigned stap_num_symbols;
+struct _stp_module {
+ /* the module name, or "" for kernel */
+ char name[STP_MODULE_NAME_LEN];
+ /* A pointer to the struct module. Note that we cannot */
+ /* trust this because as of 2.6.19, there are not yet */
+ /* any notifier hooks that will tell us when a module */
+ /* is unloading. */
+ unsigned long module;
-#endif /* _RUNTIME_H_ */
+ /* the start of the module's text and data sections */
+ unsigned long text;
+ unsigned long data;
+
+ /* how many symbols this module has that we are interested in */
+ unsigned num_symbols;
+
+ /* how many sections this module has */
+ unsigned num_sections;
+ struct _stp_symbol *sections;
+
+ /* how the symbol_data below was allocated */
+ int allocated; /* 0 = kmalloc, 1 = vmalloc */
+
+ /* an array of num_symbols _stp_symbol structs */
+ struct _stp_symbol *symbols; /* ordered by address */
+
+ /* where we stash our copy of the strtab */
+ void *symbol_data; /* private */
+};
+
+#ifndef STP_MAX_MODULES
+#define STP_MAX_MODULES 128
+#endif
+
+/* the alphabetical array of modules */
+struct _stp_module *_stp_modules[STP_MAX_MODULES];
+
+/* the array of modules ordered by addresses */
+struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES];
+
+/* the number of modules in the arrays */
+int _stp_num_modules = 0;
+
+#endif /* _STAP_SYMBOLS_H_ */
diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog
index 6b63669c..54a3c282 100644
--- a/runtime/transport/ChangeLog
+++ b/runtime/transport/ChangeLog
@@ -1,3 +1,18 @@
+2006-11-02 Martin Hunt <hunt@redhat.com>
+
+ * symbols.c: New file. Get the STP_SYMBOLS and STP_MODULE
+ messages, allocate memory and store the data.
+
+ * procfs.c (_stp_proc_write_cmd): When STP_SYMBOLS or STP_MODULE
+ request is received, call the appropriate functions.
+
+ * transport.c (_stp_handle_start): If necessary, ask staprun for
+ symbols and modules.
+ (_stp_cleanup_and_exit): Unregister module notifier.
+ (_stp_transport_close): Unregister module notifier and free module
+ memory.
+ * transport_msgs.h (enum): Add STP_MODULE and STP_SYMBOLS.
+
2006-09-26 David Smith <dsmith@redhat.com>
* transport.c: Changed 'stpd' references to 'staprun'.
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
index b0b03a73..2605e8f1 100644
--- a/runtime/transport/procfs.c
+++ b/runtime/transport/procfs.c
@@ -82,6 +82,7 @@ static ssize_t _stp_proc_write_cmd (struct file *file, const char __user *buf,
//printk ("_stp_proc_write_cmd. count:%d type:%d\n", count, type);
count -= sizeof(int);
+ buf += sizeof(int);
switch (type) {
case STP_START:
@@ -94,16 +95,23 @@ static ssize_t _stp_proc_write_cmd (struct file *file, const char __user *buf,
_stp_handle_start (&st);
break;
}
+
+ case STP_SYMBOLS:
+ count = _stp_do_symbols(buf, count);
+ break;
+ case STP_MODULE:
+ count = _stp_do_module(buf, count);
+ break;
case STP_EXIT:
_stp_exit_flag = 1;
break;
case STP_TRANSPORT_INFO:
{
struct transport_info ti;
- //printk("STP_TRANSPORT_INFO %d %d\n", count, sizeof(struct transport_info));
+ kbug("STP_TRANSPORT_INFO %d %d\n", (int)count, (int)sizeof(struct transport_info));
if (count < sizeof(struct transport_info))
return 0;
- if (copy_from_user (&ti, &buf[4], sizeof(struct transport_info)))
+ if (copy_from_user (&ti, buf, sizeof(struct transport_info)))
return -EFAULT;
if (_stp_transport_open (&ti) < 0)
return -1;
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
new file mode 100644
index 00000000..e583103f
--- /dev/null
+++ b/runtime/transport/symbols.c
@@ -0,0 +1,420 @@
+/* -*- linux-c -*-
+ * symbols.c - stp symbol and module functions
+ *
+ * Copyright (C) Red Hat Inc, 2006
+ *
+ * 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 _SYMBOLS_C_
+#define _SYMBOLS_C_
+#include "../sym.h"
+#include <linux/sort.h>
+
+spinlock_t _stp_module_lock = SPIN_LOCK_UNLOCKED;
+#define STP_TRYLOCK_MODULES ({ \
+ int numtrylock = 0; \
+ while (!spin_trylock_irqsave (&_stp_module_lock, flags) && (++numtrylock < MAXTRYLOCK)) \
+ ndelay (TRYLOCKDELAY); \
+ (numtrylock >= MAXTRYLOCK); \
+ })
+#define STP_LOCK_MODULES spin_lock_irqsave(&_stp_module_lock, flags)
+#define STP_UNLOCK_MODULES spin_unlock_irqrestore(&_stp_module_lock, flags)
+
+static char *_stp_symbol_data = NULL;
+static int _stp_symbol_state = 0;
+static char *_stp_module_data = NULL;
+static int _stp_module_state = 0;
+
+
+/* these are all the symbol types we are interested in */
+static int _stp_sym_type_ok(int type)
+{
+ switch (type) {
+ case 'T':
+ case 't':
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/* From a module struct, scan the symtab and figure out how much space */
+/* we need to store all the parts we are interested in */
+static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize)
+{
+ int i;
+ unsigned num = 0, datasize = 0;
+ for (i=0; i < m->num_symtab; i++) {
+ char *str = (char *)(m->strtab + m->symtab[i].st_name);
+ if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) {
+ datasize += strlen(str)+1;
+ num++;
+ }
+ }
+ *dsize = datasize;
+ return num;
+}
+
+/* allocate space for a module and symbols */
+static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize)
+{
+ struct _stp_module *mod = (struct _stp_module *)kmalloc(sizeof(struct _stp_module), GFP_KERNEL);
+ if (mod == NULL)
+ goto bad;
+
+ memset(mod, 0, sizeof(struct _stp_module));
+ mod->symbols = (struct _stp_symbol *)kmalloc(num * sizeof(struct _stp_symbol), GFP_KERNEL);
+ if (mod->symbols == NULL) {
+ mod->symbols = (struct _stp_symbol *)vmalloc(num * sizeof(struct _stp_symbol));
+ if (mod->symbols == NULL)
+ goto bad;
+ mod->allocated = 1;
+ }
+
+ mod->symbol_data = kmalloc(datasize, GFP_KERNEL);
+ if (mod->symbol_data == NULL) {
+ mod->symbol_data = vmalloc(datasize);
+ if (mod->symbol_data == NULL)
+ goto bad;
+ mod->allocated |= 2;
+ }
+ mod->num_symbols = num;
+ return mod;
+
+bad:
+ if (mod)
+ kfree(mod);
+ if (mod->allocated && mod->symbols)
+ vfree(mod->symbols);
+ else
+ kfree(mod->symbols);
+ return NULL;
+}
+
+static struct _stp_module * _stp_alloc_module_from_module (struct module *m)
+{
+ unsigned datasize, num = _stp_get_sym_sizes(m, &datasize);
+ return _stp_alloc_module(num, datasize);
+}
+
+/* Delete a module and free its memory. */
+/* The lock should already be held before calling this. */
+static void _stp_del_module(struct _stp_module *mod)
+{
+ int i, num;
+
+ kbug("deleting %s\n", mod->name);
+
+ /* remove module from the arrays */
+ for (num = 1; num < _stp_num_modules; num++) {
+ if (_stp_modules[num] == mod)
+ break;
+ }
+ if (num >= _stp_num_modules)
+ return;
+
+ for (i = num; i < _stp_num_modules-1; i++)
+ _stp_modules[i] = _stp_modules[i+1];
+
+ for (num = 1; num < _stp_num_modules; num++) {
+ if (_stp_modules_by_addr[num] == mod)
+ break;
+ }
+ for (i = num; i < _stp_num_modules-1; i++)
+ _stp_modules_by_addr[i] = _stp_modules_by_addr[i+1];
+
+ _stp_num_modules--;
+
+ /* free symbol memory */
+ if (mod->num_symbols) {
+ if (mod->allocated & 1)
+ vfree(mod->symbols);
+ else
+ kfree(mod->symbols);
+ if (mod->allocated & 2)
+ vfree(mod->symbol_data);
+ else
+ kfree(mod->symbol_data);
+ }
+ if (mod->sections)
+ kfree(mod->sections);
+
+ /* free module memory */
+ kfree(mod);
+}
+
+static void _stp_free_modules(void)
+{
+ int i;
+ unsigned long flags;
+
+ STP_LOCK_MODULES;
+ for (i = _stp_num_modules - 1; i >= 0; i--)
+ _stp_del_module(_stp_modules[i]);
+ STP_UNLOCK_MODULES;
+}
+
+static unsigned long _stp_kallsyms_lookup_name(const char *name);
+
+/* process the KERNEL symbols */
+static int _stp_do_symbols(const char __user *buf, int count)
+{
+ unsigned datasize, num;
+ int i;
+ struct _stp_symbol *s;
+
+ switch (_stp_symbol_state) {
+ case 0:
+ if (count != 8) {
+ printk("unexpected systemtap error: _stp_do_symbols: count=%d\n", count);
+ return -EFAULT;
+ }
+ if (get_user(num, (unsigned __user *)buf))
+ return -EFAULT;
+ if (get_user(datasize, (unsigned __user *)(buf+4)))
+ return -EFAULT;
+ kbug("num=%d datasize=%d\n", num, datasize);
+
+ _stp_modules[0] = _stp_alloc_module(num, datasize);
+ if (_stp_modules[0] == NULL) {
+ printk("unexpected systemtap error: cannot allocate memory\n");
+ return -EFAULT;
+ }
+ _stp_symbol_state = 1;
+ break;
+ case 1:
+ if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count))
+ return -EFAULT;
+ kbug("got stap_symbols, count=%d\n", count);
+ _stp_symbol_state = 2;
+ break;
+ case 2:
+ if (copy_from_user (_stp_modules[0]->symbol_data, buf, count))
+ return -EFAULT;
+ kbug("got symbol data, count=%d\n", count);
+ _stp_num_modules = 1;
+
+
+ s = _stp_modules[0]->symbols;
+ for (i = 0; i < _stp_modules[0]->num_symbols; i++)
+ s[i].symbol += (long)_stp_modules[0]->symbol_data;
+ _stp_symbol_state = 3;
+ _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext");
+ _stp_modules_by_addr[0] = _stp_modules[0];
+ break;
+ default:
+ printk("systemtap error: unexpected symbol data of size %d.\n", count);
+ }
+ return count;
+}
+
+static int _stp_compare_addr(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;
+}
+
+static void _stp_swap_symbol(void *x, void *y, int size)
+{
+ struct _stp_symbol *a = (struct _stp_symbol *)x;
+ struct _stp_symbol *b = (struct _stp_symbol *)y;
+ unsigned long addr = a->addr;
+ const char *symbol = a->symbol;
+ a->addr = b->addr;
+ a->symbol = b->symbol;
+ b->addr = addr;
+ b->symbol = symbol;
+}
+
+
+/* Create a new _stp_module and load the symbols */
+static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
+{
+ int i, num=0;
+ struct module *m = (struct module *)imod->module;
+ struct _stp_module *mod = NULL;
+ char *dataptr;
+
+ if (m == NULL) {
+ kbug("imod->module is NULL\n");
+ return NULL;
+ }
+ if (try_module_get(m)) {
+
+ mod = _stp_alloc_module_from_module(m);
+ if (mod == NULL) {
+ module_put(m);
+ printk("Systemtap failed to allocate memory for module.\n");
+ return NULL;
+ }
+
+ strlcpy(mod->name, imod->name, STP_MODULE_NAME_LEN);
+ mod->module = imod->module;
+ mod->text = imod->text;
+ mod->data = imod->data;
+ mod->num_sections = imod->num_sections;
+ mod->sections = imod->sections;
+
+ /* now copy all the symbols we are interested in */
+ dataptr = mod->symbol_data;
+ for (i=0; i < m->num_symtab; i++) {
+ char *str = (char *)(m->strtab + m->symtab[i].st_name);
+ if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) {
+ mod->symbols[num].symbol = dataptr;
+ mod->symbols[num].addr = m->symtab[i].st_value;
+ while (*str) *dataptr++ = *str++;
+ *dataptr++ = 0;
+ num++;
+ }
+ }
+ module_put(m);
+
+ /* sort symbols by address */
+ sort (mod->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol);
+ }
+ return mod;
+}
+
+/* Do we already have this module? */
+static int _stp_module_exists(struct _stp_module *mod)
+{
+ int i, res;
+ unsigned long flags;
+ kbug("exists? %s\n", mod->name);
+ STP_LOCK_MODULES;
+ for (i = 1; i < _stp_num_modules; i++) {
+ res = strcmp(_stp_modules[i]->name, mod->name);
+ if (res > 0)
+ break;
+ if (res == 0 && _stp_modules[i]->module == mod->module) {
+ STP_UNLOCK_MODULES;
+ return 1;
+ }
+ }
+ STP_UNLOCK_MODULES;
+ return 0;
+}
+
+static void _stp_ins_module(struct _stp_module *mod)
+{
+ int i, num, res;
+ unsigned long flags;
+
+ kbug("insert %s\n", mod->name);
+
+ STP_LOCK_MODULES;
+
+ /* insert alphabetically in _stp_modules[] */
+ for (num = 1; num < _stp_num_modules; num++) {
+ res = strcmp(_stp_modules[num]->name, mod->name);
+ if (res < 0)
+ continue;
+ if (res > 0)
+ break;
+ _stp_del_module(_stp_modules[num]);
+ break;
+ }
+ for (i = _stp_num_modules; i > num; i--)
+ _stp_modules[i] = _stp_modules[i-1];
+ _stp_modules[num] = mod;
+
+ /* insert by text address in _stp_modules_by_addr[] */
+ for (num = 1; num < _stp_num_modules; num++) {
+ if (_stp_modules_by_addr[num]->text > mod->text)
+ break;
+ }
+ for (i = _stp_num_modules; i > num; i--)
+ _stp_modules_by_addr[i] = _stp_modules_by_addr[i-1];
+ _stp_modules_by_addr[num] = mod;
+
+ _stp_num_modules++;
+
+ STP_UNLOCK_MODULES;
+}
+
+
+/* Called from procfs.c when a STP_MODULE msg is received */
+static int _stp_do_module(const char __user *buf, int count)
+{
+ struct _stp_module tmpmod, *mod;
+ int i;
+
+ if (count < sizeof(tmpmod)) {
+ printk("_stp_do_modules: expected %ld and got %d\n", sizeof(tmpmod), count);
+ return -EFAULT;
+ }
+ if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod)))
+ return -EFAULT;
+
+ kbug("Got module %s, count=%d(0x%x)\n", tmpmod.name, count,count);
+
+ if (_stp_module_exists(&tmpmod))
+ return count;
+
+ /* copy in section data */
+ tmpmod.sections = kmalloc(count - sizeof(tmpmod), GFP_KERNEL);
+ if (tmpmod.sections == NULL) {
+ printk("_stp_do_module: unable to allocate memory.\n");
+ return -EFAULT;
+ }
+ if (copy_from_user ((char *)tmpmod.sections, buf+sizeof(tmpmod), count-sizeof(tmpmod))) {
+ kfree(tmpmod.sections);
+ return -EFAULT;
+ }
+ for (i = 0; i < tmpmod.num_sections; i++) {
+ tmpmod.sections[i].symbol =
+ (char *)((long)tmpmod.sections[i].symbol
+ + (long)((long)tmpmod.sections + tmpmod.num_sections * sizeof(struct _stp_symbol)));
+ }
+
+ #ifdef DEBUG
+ for (i = 0; i < tmpmod.num_sections; i++)
+ printk("section %d (stored at %p): %s %lx\n", i, &tmpmod.sections[i], tmpmod.sections[i].symbol, tmpmod.sections[i].addr);
+ #endif
+
+ /* load symbols from tmpmod.module to mod */
+ mod = _stp_load_module_symbols(&tmpmod);
+ if (mod == NULL) {
+ kfree(tmpmod.sections);
+ return -EFAULT;
+ }
+
+ _stp_ins_module(mod);
+
+ return count;
+}
+
+static int _stp_transport_send (int type, void *data, int len);
+
+static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+#ifdef CONFIG_MODULES
+ struct module *mod = (struct module *)data;
+ struct _stp_module rmod;
+
+ switch (val) {
+ case MODULE_STATE_COMING:
+ dbug("module %s loaded\n", mod->name);
+ strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN);
+ _stp_transport_send(STP_MODULE, &rmod, sizeof(struct _stp_module));
+ break;
+ default:
+ printk("module loaded? val=%ld\n", val);
+ }
+#endif
+ return 0;
+}
+
+static struct notifier_block _stp_module_load_nb = {
+ .notifier_call = _stp_module_load_notify,
+};
+
+#endif /* _SYMBOLS_C_ */
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 70c0f157..6e9c9ae1 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include "transport.h"
#include "time.c"
+#include "symbols.c"
#ifdef STP_RELAYFS
#include "relayfs.c"
@@ -49,7 +50,7 @@ int _stp_transport_open(struct transport_info *info);
#include "procfs.c"
/* send commands with timeout and retry */
-int _stp_transport_send (int type, void *data, int len)
+static int _stp_transport_send (int type, void *data, int len)
{
int err, trylimit = 50;
while ((err = _stp_write(type, data, len)) < 0 && trylimit--)
@@ -58,7 +59,7 @@ int _stp_transport_send (int type, void *data, int len)
}
#ifndef STP_RELAYFS
-int _stp_transport_write (void *data, int len)
+static int _stp_transport_write (void *data, int len)
{
/* when _stp_exit_called is set, we are in probe_exit() and we can sleep */
if (_stp_exit_called)
@@ -91,10 +92,36 @@ static void _stp_handle_buf_info(int *cpuptr)
/*
* _stp_handle_start - handle STP_START
*/
+
void _stp_handle_start (struct transport_start *st)
{
+#ifdef CONFIG_MODULES
+ static int got_modules=0;
+#endif
+
kbug ("stp_handle_start pid=%d\n", st->pid);
+ /* we've got a start request, but first, grab kernel symbols if we need them */
+ if (_stp_num_modules == 0) {
+ char tmp = 0;
+ _stp_transport_send(STP_SYMBOLS, &tmp, 1);
+ return;
+ }
+
+#ifdef CONFIG_MODULES
+ /* grab current module addresses if we haven't already */
+ if (got_modules == 0) {
+ struct _stp_module mod;
+ strcpy(mod.name, "");
+ got_modules = 1;
+ _stp_transport_send(STP_MODULE, &mod, sizeof(struct _stp_module));
+ return;
+ }
+
+ if (register_module_notifier(&_stp_module_load_nb))
+ printk("Systemtap error: failed to load module notifier\n");
+#endif
+
/* note: st->pid is actually the return code for the reply packet */
st->pid = probe_start();
atomic_set(&_stp_start_finished,1);
@@ -128,6 +155,9 @@ static void _stp_cleanup_and_exit (int dont_rmmod)
if (!_stp_exit_called) {
int failures;
+#ifdef CONFIG_MODULES
+ unregister_module_notifier(&_stp_module_load_nb);
+#endif
/* we only want to do this stuff once */
_stp_exit_called = 1;
@@ -197,13 +227,13 @@ void _stp_transport_close()
if (_stp_transport_mode == STP_TRANSPORT_RELAYFS)
_stp_relayfs_close(_stp_chan, _stp_dir);
#endif
+#ifdef CONFIG_MODULES
+ unregister_module_notifier(&_stp_module_load_nb);
+#endif
_stp_unregister_procfs();
-
+ _stp_free_modules();
_stp_kill_time();
-
- /* free print buffers */
- _stp_print_cleanup();
-
+ _stp_print_cleanup(); /* free print buffers */
kbug("---- CLOSED ----\n");
}
@@ -317,5 +347,4 @@ static int _stp_relay_write (const void *data, unsigned length)
return length;
}
#endif
-
#endif /* _TRANSPORT_C_ */
diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h
index 6d0b2c34..282762ab 100644
--- a/runtime/transport/transport_msgs.h
+++ b/runtime/transport/transport_msgs.h
@@ -16,6 +16,8 @@ enum
STP_EXIT,
STP_OOB_DATA,
STP_SYSTEM,
+ STP_SYMBOLS,
+ STP_MODULE,
};
/* control channel command structs */
@@ -56,3 +58,5 @@ struct cmd_info
char cmd[128];
};
+
+
diff --git a/session.h b/session.h
index 95d97155..0a0bfb8a 100644
--- a/session.h
+++ b/session.h
@@ -92,6 +92,7 @@ struct systemtap_session
bool merge;
int buffer_size;
unsigned perfmon;
+ bool symtab;
// Cache data
bool use_cache;
diff --git a/tapsets.cxx b/tapsets.cxx
index eaa635d4..dc0fc3c1 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -3218,58 +3218,6 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "/* ---- dwarf probes ---- */";
- // XXX: Until staprun provides us a run-time module/section/address
- // table, we take matters into our own hands.
- s.op->newline() << "struct stap_module { const char* module; const char* section; unsigned long address; } stap_modules[] = {";
- s.op->indent(1);
- glob_t globbuf;
- int rc = glob ("/sys/module/*", 0, NULL, &globbuf);
- if (!rc) for (unsigned j=0; j<globbuf.gl_pathc; j++)
- {
- string module = strrchr (globbuf.gl_pathv[j], '/') + 1;
- glob_t globbuf2;
- string moddir = string("/sys/module/") + module + string("/sections/*");
- int rc2 = glob (moddir.c_str(), GLOB_PERIOD, NULL, &globbuf2);
- if (!rc2) for (unsigned k=0; k<globbuf2.gl_pathc; k++)
- {
- string section = strrchr (globbuf2.gl_pathv[k], '/') + 1;
- ifstream file (globbuf2.gl_pathv[k]);
- if (! file.good()) { file.close(); continue; } // might include "." and "..", bugger!
- string hex_address;
- try { file >> hex_address; } catch (...) { file.close(); continue; }
- file.close ();
- if (s.verbose > 2)
- clog << "found module=" << module << " section=" << section << " base=" << hex_address << endl;
- // we don't need to use quoted_lex_blah since module/section names are vanilla
- s.op->newline() << "{ \"" << module << "\", \"" << section << "\", " << hex_address << "UL },";
- }
- if (!rc2) globfree (& globbuf2);
- }
- if (!rc) globfree (& globbuf);
- s.op->newline() << "{ \"\", \"\", 0 }"; // sentinel
- s.op->newline(-1) << "};";
-
- // A convenient lookup function for this table
- s.op->newline() << "static unsigned long module_relocate (const char *module, const char *section, unsigned long offset) {";
- s.op->newline(1) << "static struct stap_module *last = & stap_modules[0];"; // a one-entry TLB
- s.op->newline() << "if (! module) { return offset; }"; // non-relocatable? just hand it back.
- // emit code to look at "one-entry TLB"; assumes last-> points no farther than sentinel
- s.op->newline() << "if (!strcmp (module, last->module) && !strcmp (section, last->section))";
- s.op->newline(1) << "return offset + last->address;";
- // emit code to look at it the long way ... simple but slow.
- // Luckily, the later code makes sure that probes are relocated in a
- // sorted sequence by module, so the TLB hit rate should be
- // excellent.
- s.op->newline(-1) << "last = & stap_modules[0];";
- s.op->newline() << "while (last->module && last->section && last->module[0]) {"; // sentinel
- s.op->newline(1) << "if (!strcmp (module, last->module) && !strcmp (section, last->section))";
- s.op->newline(1) << "return offset + last->address;";
- s.op->newline(-1) << "last ++;";
- s.op->newline(-1) << "}";
- s.op->newline() << "last = & stap_modules[0];"; // important: reset to some valid entry
- s.op->newline() << "return 0;"; // not found in entire module table
- s.op->newline(-1) << "}";
-
// Forward declare the master entry functions
s.op->newline() << "static int enter_kprobe_probe (struct kprobe *inst,";
s.op->line() << " struct pt_regs *regs);";
@@ -3340,7 +3288,7 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s)
{
s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];";
- s.op->newline() << "unsigned long relocated_addr = module_relocate (sdp->module, sdp->section, sdp->address);";
+ s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address);";
s.op->newline() << "if (relocated_addr == 0) continue;"; // quietly; assume module is absent
s.op->newline() << "if (sdp->return_p) {";
s.op->newline(1) << "sdp->u.krp.kp.addr = (void *) relocated_addr;";
diff --git a/translate.cxx b/translate.cxx
index 55e701fe..1f2e47f0 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -3768,7 +3768,6 @@ c_unparser::visit_hist_op (hist_op* e)
assert(false);
}
-
int
emit_symbol_data (systemtap_session& s)
{
@@ -3786,6 +3785,13 @@ emit_symbol_data (systemtap_session& s)
string sorted_kallsyms = s.tmpdir + "/symbols.sorted";
string sortcmd = "grep \" [AtT] \" /proc/kallsyms | ";
+ if (s.symtab == false)
+ {
+ s.op->newline() << "struct stap_symbol *stap_symbols;";
+ s.op->newline() << "unsigned stap_num_symbols = 0;\n";
+ return 0;
+ }
+
sortcmd += "sort ";
#if __LP64__
sortcmd += "-k 1,16 ";
@@ -3807,7 +3813,7 @@ emit_symbol_data (systemtap_session& s)
s.op->newline() << "\n\n#include \"stap-symbols.h\"";
unsigned i=0;
- kallsyms_out << "struct stap_symbol stap_symbols [] = {";
+ kallsyms_out << "struct stap_symbol _stp_stap_symbols [] = {";
string lastaddr;
while (! kallsyms.eof())
{
@@ -3833,6 +3839,7 @@ emit_symbol_data (systemtap_session& s)
}
}
kallsyms_out << "};\n";
+ kallsyms_out << "struct stap_symbol *stap_symbols = _stp_stap_symbols;";
kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n";
}
@@ -3978,7 +3985,7 @@ translate_pass (systemtap_session& s)
}
rc |= emit_symbol_data (s);
-
+
s.op->line() << "\n";
delete s.op;