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