diff options
author | hunt <hunt> | 2006-11-02 18:37:00 +0000 |
---|---|---|
committer | hunt <hunt> | 2006-11-02 18:37:00 +0000 |
commit | f1bad60c76d79f01a87e4128df266bf4252a71e0 (patch) | |
tree | 5114f087d844e702253a439efbcc36e310268a4b | |
parent | 202e1828643725d7bebef76c48cbaa28c463cee3 (diff) | |
download | systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.gz systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.tar.xz systemtap-steved-f1bad60c76d79f01a87e4128df266bf4252a71e0.zip |
New dynamic module and symbol handling code.
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 20 | ||||
-rw-r--r-- | main.cxx | 1 | ||||
-rw-r--r-- | runtime/stpd/ChangeLog | 13 | ||||
-rw-r--r-- | runtime/stpd/Makefile | 14 | ||||
-rw-r--r-- | runtime/stpd/librelay.c | 88 | ||||
-rw-r--r-- | runtime/stpd/librelay.h | 16 | ||||
-rw-r--r-- | runtime/stpd/symbols.c | 226 | ||||
-rw-r--r-- | runtime/sym.c | 101 | ||||
-rw-r--r-- | runtime/sym.h | 53 | ||||
-rw-r--r-- | runtime/transport/ChangeLog | 15 | ||||
-rw-r--r-- | runtime/transport/procfs.c | 12 | ||||
-rw-r--r-- | runtime/transport/symbols.c | 420 | ||||
-rw-r--r-- | runtime/transport/transport.c | 45 | ||||
-rw-r--r-- | runtime/transport/transport_msgs.h | 4 | ||||
-rw-r--r-- | session.h | 1 | ||||
-rw-r--r-- | tapsets.cxx | 54 | ||||
-rw-r--r-- | translate.cxx | 13 |
19 files changed, 973 insertions, 143 deletions
@@ -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 @@ -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]; }; + + @@ -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; |