summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-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
12 files changed, 923 insertions, 84 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);
+ }
+}
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];
};
+
+