summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/probes.c152
-rw-r--r--runtime/staprun/staprun.c3
-rw-r--r--runtime/sym.c140
-rw-r--r--runtime/sym.h55
-rw-r--r--runtime/transport/symbols.c571
-rw-r--r--runtime/transport/transport.c18
-rw-r--r--runtime/unwind.c17
-rw-r--r--translate.cxx129
8 files changed, 198 insertions, 887 deletions
diff --git a/runtime/probes.c b/runtime/probes.c
deleted file mode 100644
index 6fe844fb..00000000
--- a/runtime/probes.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* -*- linux-c -*-
- * Functions for Registering and Unregistering Probes
- * Copyright (C) 2005 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.
- */
-
-#ifndef _PROBES_C_
-#define _PROBES_C
-
-/** @file probes.c
- * @brief Functions to assist loading and unloading groups of probes.
- */
-
-/** Unregister a group of jprobes.
- * @param probes Pointer to an array of struct jprobe.
- * @param num_probes Number of probes in the array.
- */
-
-void _stp_unregister_jprobes (struct jprobe *probes, int num_probes)
-{
- int i;
- for (i = 0; i < num_probes; i++)
- unregister_jprobe(&probes[i]);
- // dbug("All jprobes removed\n");
-}
-
-/** Register a group of jprobes.
- * @param probes Pointer to an array of struct jprobe.
- * @param num_probes Number of probes in the array.
- * @return 0 on success.
- */
-
-int _stp_register_jprobes (struct jprobe *probes, int num_probes)
-{
- int i, ret ;
- unsigned long addr;
-
- for (i = 0; i < num_probes; i++) {
- addr =kallsyms_lookup_name((char *)probes[i].kp.addr);
- if (addr == 0) {
- _stp_warn("function %s not found!\n", (char *)probes[i].kp.addr);
- ret = -1; /* FIXME */
- goto out;
- }
- // dbug("inserting jprobe at %s (%p)\n", probes[i].kp.addr, addr);
- probes[i].kp.addr = (kprobe_opcode_t *)addr;
- ret = register_jprobe(&probes[i]);
- if (ret)
- goto out;
- }
- return 0;
-out:
- _stp_warn("probe module initialization failed. Exiting...\n");
- _stp_unregister_jprobes(probes, i);
- return ret;
-}
-
-/** Unregister a group of kprobes.
- * @param probes Pointer to an array of struct kprobe.
- * @param num_probes Number of probes in the array.
- */
-
-void _stp_unregister_kprobes (struct kprobe *probes, int num_probes)
-{
- int i;
- for (i = 0; i < num_probes; i++)
- unregister_kprobe(&probes[i]);
- // dbug("All kprobes removed\n");
-}
-
-
-#ifdef USE_RET_PROBES
-/** Unregister a group of return probes.
- * @param probes Pointer to an array of struct kretprobe.
- * @param num_probes Number of probes in the array.
- */
-void _stp_unregister_kretprobes (struct kretprobe *probes, int num_probes)
-{
- int i;
- for (i = 0; i < num_probes; i++)
- unregister_kretprobe(&probes[i]);
- // dbug("All return probes removed\n");
-}
-#endif
-
-/** Register a group of kprobes.
- * @param probes Pointer to an array of struct kprobe.
- * @param num_probes Number of probes in the array.
- * @return 0 on success.
- */
-int _stp_register_kprobes (struct kprobe *probes, int num_probes)
-{
- int i, ret ;
- unsigned long addr;
-
- for (i = 0; i < num_probes; i++) {
- addr = kallsyms_lookup_name((char *)probes[i].addr);
- if (addr == 0) {
- _stp_warn("function %s not found!\n", (char *)probes[i].addr);
- ret = -1;
- goto out;
- }
- // dbug("inserting kprobe at %s (%p)\n", probes[i].addr, addr);
- probes[i].addr = (kprobe_opcode_t *)addr;
- ret = register_kprobe(&probes[i]);
- if (ret)
- goto out;
- }
- return 0;
-out:
- _stp_warn("probe module initialization failed. Exiting...\n");
- _stp_unregister_kprobes(probes, i);
- return ret;
-}
-
-#ifdef USE_RET_PROBES
-/** Register a group of return probes.
- * @param probes Pointer to an array of struct kretprobe.
- * @param num_probes Number of probes in the array.
- * @return 0 on success.
- */
-int _stp_register_kretprobes (struct kretprobe *probes, int num_probes)
-{
- int i, ret ;
- unsigned long addr;
-
- for (i = 0; i < num_probes; i++) {
- addr = kallsyms_lookup_name((char *)probes[i].kp.addr);
- if (addr == 0) {
- _stp_warn("function %s not found!\n",
- (char *)probes[i].kp.addr);
- ret = -1; /* FIXME */
- goto out;
- }
- // dbug("inserting kretprobe at %s (%p)\n", probes[i].kp.addr, addr);
- probes[i].kp.addr = (kprobe_opcode_t *)addr;
- ret = register_kretprobe(&probes[i]);
- if (ret)
- goto out;
- }
- return 0;
-out:
- _stp_warn("probe module initialization failed. Exiting...\n");
- _stp_unregister_kretprobes(probes, i);
- return ret;
-}
-#endif
-#endif /* _PROBES_C */
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index 6eb6d8b5..cef96815 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -360,7 +360,8 @@ int send_relocation_kernel ()
#endif
if ((rc == 3) && (0 == strcmp(symbol,KERNEL_RELOC_SYMBOL)))
{
- send_a_relocation ("kernel", KERNEL_RELOC_SYMBOL, address);
+ /* NB: even on ppc, we use the _stext relocation name. */
+ send_a_relocation ("kernel", "_stext", address);
/* We need nothing more from the kernel. */
fclose (kallsyms);
diff --git a/runtime/sym.c b/runtime/sym.c
index eca54a35..ab6b6069 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -25,7 +25,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
static struct _stp_module *last = NULL;
static struct _stp_symbol *last_sec;
unsigned long flags;
- int i, j;
+ unsigned i, j;
/* if module is -1, we invalidate last. _stp_del_module calls this when modules are deleted. */
if ((long)module == -1) {
@@ -35,10 +35,8 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
dbug_sym(1, "%s, %s, %lx\n", module, section, offset);
- STP_RLOCK_MODULES;
if (!module || !strcmp(section, "") /* absolute, unrelocated address */
||_stp_num_modules == 0) {
- STP_RUNLOCK_MODULES;
return offset;
}
@@ -46,122 +44,76 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
if (last) {
if (!strcmp(module, last->name) && !strcmp(section, last_sec->symbol)) {
offset += last_sec->addr;
- STP_RUNLOCK_MODULES;
- dbug_sym(1, "offset = %lx\n", offset);
+ dbug_sym(1, "cached address=%lx\n", offset);
return offset;
}
}
- /* not cached. need to scan all modules */
- if (!strcmp(module, "kernel")) {
- STP_RUNLOCK_MODULES;
-
- /* See also transport/symbols.c (_stp_do_symbols). */
- if (strcmp(section, "_stext"))
- return 0;
- else if (_stp_modules[0]->text == 0) /* kernel->text unavailable? STP_RELOCATE */
- return 0;
- else
- return offset + _stp_modules[0]->text;
- } else {
- /* relocatable module */
- for (i = 1; i < _stp_num_modules; i++) { /* skip over [0]=kernel */
- last = _stp_modules[i];
- if (strcmp(module, last->name))
- continue;
- for (j = 0; j < (int)last->num_sections; j++) {
- last_sec = &last->sections[j];
- if (!strcmp(section, last_sec->symbol)) {
- offset += last_sec->addr;
- STP_RUNLOCK_MODULES;
- dbug_sym(1, "offset = %lx\n", offset);
- return offset;
- }
- }
- }
+ for (i = 0; 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)) {
+ offset += last_sec->addr;
+ dbug_sym(1, "address=%lx\n", offset);
+ return offset;
+ }
+ }
}
- STP_RUNLOCK_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 _stp_symbol *s = _stp_modules[0]->symbols;
- unsigned num = _stp_modules[0]->num_symbols;
- unsigned i;
-
- for (i=0; i<num; i++, s++) {
- if (strcmp(name, s->symbol) == 0)
- return s->addr;
- s++;
- }
- return 0;
-}
+/* Return the module that likely contains the given address. */
+/* XXX: This query only makes sense with respect to a particular
+ address space. A more general interface would have to identify
+ the address space, and also pass back the section. */
static struct _stp_module *_stp_find_module_by_addr(unsigned long addr)
{
- unsigned begin = 0;
- unsigned end = _stp_num_modules;
-
- if (unlikely(addr < _stp_modules_by_addr[0]->text))
- return NULL;
-
- if (_stp_num_modules > 1 && addr > _stp_modules_by_addr[0]->data) {
- /* 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) */
- }
- /* check if addr is past the last module */
- if (unlikely(begin == _stp_num_modules - 1
- && (addr > _stp_modules_by_addr[begin]->text + _stp_modules_by_addr[begin]->text_size)))
- return NULL;
-
- return _stp_modules_by_addr[begin];
+ unsigned i;
+ struct _stp_module *closest_module = NULL;
+ unsigned long closest_module_offset = ~0; /* minimum[addr - module->.text] */
+
+ for (i=0; i<_stp_num_modules; i++)
+ {
+ unsigned long module_text_addr, this_module_offset;
+
+ if (_stp_modules[i]->num_sections < 1) continue;
+ module_text_addr = _stp_modules[i]->sections[0].addr; /* XXX: assume section[0]=>text */
+ if (addr < module_text_addr) continue;
+ this_module_offset = module_text_addr - addr;
+
+ if (this_module_offset < closest_module_offset)
+ {
+ closest_module = _stp_modules[i];
+ closest_module_offset = this_module_offset;
+ }
+ }
+
+ return closest_module;
}
-static struct _stp_module *_stp_get_unwind_info(unsigned long addr)
-{
- struct _stp_module *m;
- struct _stp_symbol *s;
- unsigned long flags;
- STP_RLOCK_MODULES;
- m = _stp_find_module_by_addr(addr);
- if (unlikely(m == NULL)) {
- STP_RUNLOCK_MODULES;
- return NULL;
- }
- /* Lock the module struct so it doesn't go away while being used. */
- /* Probably could never happen, but lock it to be sure for now. */
- read_lock(&m->lock);
- STP_RUNLOCK_MODULES;
- return m;
-}
-
-static const char *_stp_kallsyms_lookup(unsigned long addr,
- unsigned long *symbolsize, unsigned long *offset, char **modname, char *namebuf)
+static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
+ unsigned long *offset, char **modname, char *namebuf)
{
struct _stp_module *m;
struct _stp_symbol *s;
unsigned long flags;
unsigned end, begin = 0;
- STP_RLOCK_MODULES;
m = _stp_find_module_by_addr(addr);
if (unlikely(m == NULL)) {
- STP_RUNLOCK_MODULES;
return NULL;
}
+ /* NB: relativize the address to the (XXX) presumed text section. */
+ addr -= m->sections[0].addr;
end = m->num_symbols;
/* binary search for symbols within the module */
@@ -190,17 +142,15 @@ static const char *_stp_kallsyms_lookup(unsigned long addr,
}
if (namebuf) {
strlcpy(namebuf, s->symbol, KSYM_NAME_LEN + 1);
- STP_RUNLOCK_MODULES;
return namebuf;
} else {
- STP_RUNLOCK_MODULES;
return s->symbol;
}
}
- STP_RUNLOCK_MODULES;
return NULL;
}
+
/** Print an address symbolically.
* @param address The address to lookup.
* @note Symbolic lookups should not normally be done within
diff --git a/runtime/sym.h b/runtime/sym.h
index 0bb64c13..c7caacae 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -17,12 +17,6 @@ struct _stp_symbol {
const char *symbol;
};
-DEFINE_RWLOCK(_stp_module_lock);
-#define STP_RLOCK_MODULES read_lock_irqsave(&_stp_module_lock, flags)
-#define STP_WLOCK_MODULES write_lock_irqsave(&_stp_module_lock, flags)
-#define STP_RUNLOCK_MODULES read_unlock_irqrestore(&_stp_module_lock, flags)
-#define STP_WUNLOCK_MODULES write_unlock_irqrestore(&_stp_module_lock, flags)
-
struct _stp_module {
/* the module name, or "" for kernel */
char name[STP_MODULE_NAME_LEN];
@@ -31,59 +25,34 @@ struct _stp_module {
/* 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;
-
- /* the start of the module's text and data sections */
- unsigned long text;
- unsigned long data;
-
- uint32_t text_size;
-
- /* how many symbols this module has that we are interested in */
- uint32_t num_symbols;
-
- /* how many sections this module has */
- uint32_t num_sections;
-
- /* how the data below was allocated */
- /* 0 = kmalloc, 1 = vmalloc */
- struct {
- unsigned symbols :1;
- unsigned symbol_data :1;
- unsigned unwind_data :1;
- unsigned unwind_hdr :1;
- } allocated;
+ unsigned long module; /* XXX: why not struct module * ? */
struct _stp_symbol *sections;
-
- /* 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;
-
+ unsigned num_sections;
+ struct _stp_symbol *symbols; /* ordered by address */
+ unsigned num_symbols;
+
/* the stack unwind data for this module */
void *unwind_data;
void *unwind_hdr;
uint32_t unwind_data_len;
uint32_t unwind_hdr_len;
uint32_t unwind_is_ehframe; /* unwind data comes from .eh_frame */
- rwlock_t lock; /* lock while unwinding is happening */
-
};
-#ifndef STP_MAX_MODULES
-#define STP_MAX_MODULES 256
-#endif
-/* the alphabetical array of modules */
-struct _stp_module *_stp_modules[STP_MAX_MODULES];
+/* Defined by translator-generated stap-symbols.h. */
+struct _stp_module *_stp_modules [];
+int _stp_num_modules;
+
+#if 0
/* the array of modules ordered by addresses */
struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES];
+#endif
/* the number of modules in the arrays */
-int _stp_num_modules = 0;
+
static unsigned long _stp_kretprobe_trampoline = 0;
unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset);
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index 77263284..c868c5fd 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -16,205 +16,20 @@
#define _STP_SYMBOLS_C_
#include "../sym.h"
-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)
-{
- /* we only care about function symbols, which are in the text section */
- if (type == 'T' || type == 't')
- return 1;
- 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)
-{
- unsigned 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, sections, and symbols */
-static struct _stp_module *_stp_alloc_module(unsigned sectsize, unsigned num, unsigned datasize)
-{
- struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module));
- if (mod == NULL)
- goto bad;
-
- mod->sections = (struct _stp_symbol *)_stp_kmalloc(sectsize);
- if (mod->sections == NULL)
- goto bad;
-
- mod->symbols = (struct _stp_symbol *)_stp_kmalloc(num * sizeof(struct _stp_symbol));
- if (mod->symbols == NULL) {
- mod->symbols = (struct _stp_symbol *)_stp_vmalloc(num * sizeof(struct _stp_symbol));
- if (mod->symbols == NULL)
- goto bad;
- mod->allocated.symbols = 1;
- }
-
- mod->symbol_data = _stp_kmalloc(datasize);
- if (mod->symbol_data == NULL) {
- mod->symbol_data = _stp_vmalloc(datasize);
- if (mod->symbol_data == NULL)
- goto bad;
- mod->allocated.symbol_data = 1;
- }
-
- mod->num_symbols = num;
- return mod;
-
-bad:
- if (mod) {
- if (mod->sections)
- _stp_kfree(mod->sections);
- if (mod->symbols) {
- if (mod->allocated.symbols)
- _stp_vfree(mod->symbols);
- else
- _stp_kfree(mod->symbols);
- }
- _stp_kfree(mod);
- }
- return NULL;
-}
-
-static void _stp_free_module(struct _stp_module *mod)
-{
- /* The module write lock is held. Any prior readers of this */
- /* module's data will have read locks and need to finish before */
- /* the memory is freed. */
- write_lock(&mod->lock);
- write_unlock(&mod->lock); /* there will be no more readers */
-
- /* Free symbol memory */
- /* If symbol_data wasn't allocated, then symbols weren't either. */
- if (mod->symbol_data) {
- if (mod->symbols) {
- if (mod->allocated.symbols)
- _stp_vfree(mod->symbols);
- else
- _stp_kfree(mod->symbols);
- }
- if (mod->allocated.symbol_data)
- _stp_vfree(mod->symbol_data);
- else
- _stp_kfree(mod->symbol_data);
- }
- if (mod->unwind_data) {
- if (mod->allocated.unwind_data)
- _stp_vfree(mod->unwind_data);
- else
- _stp_kfree(mod->unwind_data);
- }
- if (mod->unwind_hdr) {
- if (mod->allocated.unwind_hdr)
- _stp_vfree(mod->unwind_hdr);
- else
- _stp_kfree(mod->unwind_hdr);
- }
- if (mod->sections)
- _stp_kfree(mod->sections);
-
- /* free module memory */
- _stp_kfree(mod);
-}
-
-/* Delete a module and free its memory. */
-/* The module lock should already be held before calling this. */
-static void _stp_del_module(struct _stp_module *mod)
-{
- int i, num;
-
- dbug_sym(1, "deleting module %s\n", mod->name);
-
- /* signal relocation code to clear its cache */
- _stp_module_relocate((char *)-1, NULL, 0);
-
- /* remove module from the arrays */
- for (num = 0; 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 = 0; 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--;
-
- _stp_free_module(mod);
-}
-
-static void _stp_free_modules(void)
-{
- int i;
- /* This only happens when the systemtap module unloads */
- /* so there is no need for locks. */
- for (i = _stp_num_modules - 1; i >= 0; i--)
- _stp_del_module(_stp_modules[i]);
-}
-
-static unsigned long _stp_kallsyms_lookup_name(const char *name);
static void _stp_create_unwind_hdr(struct _stp_module *m);
-extern unsigned _stp_num_kernel_symbols;
-extern struct _stp_symbol _stp_kernel_symbols[];
-
-/* initialize the kernel symbols */
-static int _stp_init_kernel_symbols(void)
-{
- _stp_modules[0] = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module));
- if (_stp_modules[0] == NULL) {
- _dbug("cannot allocate memory\n");
- return -1;
- }
- _stp_modules[0]->symbols = _stp_kernel_symbols;
- _stp_modules[0]->num_symbols = _stp_num_kernel_symbols;
- rwlock_init(&_stp_modules[0]->lock);
- _stp_num_modules = 1;
-
- /* Note: this mapping is used by kernel/_stext pseudo-relocations. */
- _stp_modules[0]->text = 0; /* This should be set by a STP_RELOCATE message. */
- _stp_modules[0]->data = 0; /* XXX */
- _stp_modules[0]->text_size = 0; /* XXX */
-
- _stp_kretprobe_trampoline = 0; /* XXX */
- _stp_modules_by_addr[0] = _stp_modules[0];
-
- dbug_sym(2, "systemtap supplied %u kernel symbols\n", _stp_num_kernel_symbols);
-
- return 0;
-}
-
static void _stp_do_relocation(const char __user *buf, size_t count)
{
struct _stp_msg_relocation msg;
+ unsigned mi, si;
+
if (sizeof(msg) != count)
{
- errk ("STP_RELOCATE message size mismatch (%u vs %u)\n", sizeof(msg), count);
+ errk ("STP_RELOCATE message size mismatch (%lu vs %lu)\n",
+ (long unsigned) sizeof(msg), (long unsigned) count);
return;
}
@@ -223,107 +38,28 @@ static void _stp_do_relocation(const char __user *buf, size_t count)
dbug_sym(2, "relocate (%s %s 0x%lx)\n", msg.module, msg.reloc, (unsigned long) msg.address);
- if (!strcmp (msg.module, "kernel") &&
- !strcmp (msg.reloc, "_stext"))
-
- {
- unsigned i;
-
- _stp_modules[0]->text = (unsigned long) msg.address;
- /* Now, relocate all the elements in the kernel symbol table.
- We should at that point arrive at a strict subset of the
- /proc/kallsyms table. */
+ /* Save the relocation value. XXX: While keeping the data here is
+ fine for the kernel address space ("kernel" and "*.ko" modules),
+ it is NOT fine for user-space apps. They need a separate
+ relocation values for each address space, since the same shared
+ libraries/executables can be mapped in at different
+ addresses. */
- for (i=0; i<_stp_modules[0]->num_symbols; i++)
- _stp_modules[0]->symbols[i].addr += msg.address;
- }
-}
-
-
-#if 0
-static void _stp_do_unwind_data(const char __user *buf, size_t count)
-{
- u32 unwind_len;
- unsigned long flags;
- char name[STP_MODULE_NAME_LEN];
- int i;
- struct _stp_module *m;
-
- dbug_unwind(1, "got unwind data, count=%d\n", count);
-
- if (count < STP_MODULE_NAME_LEN + sizeof(unwind_len)) {
- dbug_unwind(1, "unwind message too short\n");
- return;
- }
- if (strncpy_from_user(name, buf, STP_MODULE_NAME_LEN) < 0) {
- errk("userspace copy failed\n");
- return;
- }
- dbug_unwind(1, "name=%s\n", name);
- if (!strcmp(name,"*")) {
- /* OK, all initial unwind data received. Ready to go. */
- _stp_ctl_send(STP_TRANSPORT, NULL, 0);
- return;
- }
- count -= STP_MODULE_NAME_LEN;
- buf += STP_MODULE_NAME_LEN;
-
- if (get_user(unwind_len, (u32 __user *)buf)) {
- errk("userspace copy failed\n");
- return;
- }
- count -= sizeof(unwind_len);
- buf += sizeof(unwind_len);
- if (count != unwind_len) {
- dbug_unwind(1, "count=%d unwind_len=%d\n", (int)count, (int)unwind_len);
- return;
- }
+ for (mi=0; mi<_stp_num_modules; mi++)
+ {
+ if (strcmp (_stp_modules[mi]->name, msg.module))
+ continue;
- STP_RLOCK_MODULES;
- for (i = 0; i < _stp_num_modules; i++) {
- if (strcmp(name, _stp_modules[i]->name) == 0)
- break;
- }
- if (unlikely(i == _stp_num_modules)) {
- dbug_unwind(1, "module %s not found!\n", name);
- STP_RUNLOCK_MODULES;
- return;
- }
- m = _stp_modules[i];
- write_lock(&m->lock);
- STP_RUNLOCK_MODULES;
+ for (si=0; si<_stp_modules[mi]->num_sections; si++)
+ {
+ if (strcmp (_stp_modules[mi]->sections[si].symbol, msg.reloc))
+ continue;
- /* allocate space for unwind data */
- m->unwind_data = _stp_kmalloc(count);
- if (unlikely(m->unwind_data == NULL)) {
- m->unwind_data = _stp_vmalloc(count);
- if (m->unwind_data == NULL) {
- errk("kmalloc failed\n");
- goto done;
- }
- m->allocated.unwind_data = 1;
- }
-
- if (unlikely(copy_from_user(m->unwind_data, buf, count))) {
- errk("userspace copy failed\n");
- if (m->unwind_data) {
- if (m->allocated.unwind_data)
- _stp_vfree(m->unwind_data);
- else
- _stp_kfree(m->unwind_data);
- m->unwind_data = NULL;
- }
- goto done;
- }
- m->unwind_data_len = count;
-#ifdef STP_USE_DWARF_UNWINDER
- _stp_create_unwind_hdr(m);
-#endif
-done:
- write_unlock(&m->lock);
+ _stp_modules[mi]->sections[si].addr = msg.address;
+ } /* loop over sections */
+ } /* loop over modules */
}
-#endif /* do_unwind_data; not used */
static int _stp_compare_addr(const void *p1, const void *p2)
@@ -428,270 +164,5 @@ static int _stp_section_is_interesting(const char *name)
return ret;
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
-struct module_sect_attr
-{
- struct module_attribute mattr;
- char *name;
- unsigned long address;
-};
-
-struct module_sect_attrs
-{
- struct attribute_group grp;
- unsigned int nsections;
- struct module_sect_attr attrs[0];
-};
-#endif
-
-/* Create a new _stp_module and load the symbols */
-static struct _stp_module *_stp_load_module_symbols(struct module *mod)
-{
- int i, num, overflow = 0;
- struct module_sect_attrs *sa = mod->sect_attrs;
- struct attribute_group *sag = & sa->grp;
- unsigned sect_size = 0, sect_num = 0, sym_size, sym_num;
- struct _stp_module *sm;
- char *dataptr, *endptr;
- unsigned nsections = 0;
-
-#ifdef STAPCONF_MODULE_NSECTIONS
- nsections = sa->nsections;
-#else
- /* count section attributes on older kernel */
- struct attribute** gattr;
- for (gattr = sag->attrs; *gattr; gattr++)
- nsections++;
- dbug_sym(2, "\tcount %d\n", nsections);
-#endif
-
- /* calculate how much space to allocate for section strings */
- for (i = 0; i < nsections; i++) {
- if (_stp_section_is_interesting(sa->attrs[i].name)) {
- sect_num++;
- sect_size += strlen(sa->attrs[i].name) + 1;
- dbug_sym(2, "\t%s\t%lx\n", sa->attrs[i].name, sa->attrs[i].address);
- }
- }
- sect_size += sect_num * sizeof(struct _stp_symbol);
-
- /* and how much space for symbols */
- sym_num = _stp_get_sym_sizes(mod, &sym_size);
-
- sm = _stp_alloc_module(sect_size, sym_num, sym_size);
- if (!sm) {
- errk("failed to allocate memory for module.\n");
- return NULL;
- }
-
- strlcpy(sm->name, mod->name, STP_MODULE_NAME_LEN);
- sm->module = (unsigned long)mod;
- sm->text = (unsigned long)mod->module_core;
- sm->text_size = mod->core_text_size;
- sm->data = 0; /* fixme */
- sm->num_sections = sect_num;
- rwlock_init(&sm->lock);
-
- /* copy in section data */
- dataptr = (char *)((long)sm->sections + sect_num * sizeof(struct _stp_symbol));
- endptr = (char *)((long)sm->sections + sect_size);
- num = 0;
- for (i = 0; i < nsections; i++) {
- size_t len, maxlen;
- if (_stp_section_is_interesting(sa->attrs[i].name)) {
- sm->sections[num].addr = sa->attrs[i].address;
- sm->sections[num].symbol = dataptr;
- maxlen = (size_t) (endptr - dataptr);
- len = strlcpy(dataptr, sa->attrs[i].name, maxlen);
- if (unlikely(len >= maxlen)) {
- _dbug("dataptr=%lx endptr=%lx len=%d maxlen=%d\n", dataptr, endptr, len, maxlen);
- overflow = 1;
- }
- dataptr += len + 1;
- num++;
- }
- }
- if (unlikely(overflow)) {
- errk("Section names truncated!!! Should never happen!!\n");
- *endptr = 0;
- overflow = 0;
- }
-
- /* now copy all the symbols we are interested in */
- dataptr = sm->symbol_data;
- endptr = dataptr + sym_size - 1;
- num = 0;
- for (i = 0; i < mod->num_symtab; i++) {
- char *str = (char *)(mod->strtab + mod->symtab[i].st_name);
- if (*str != '\0' && _stp_sym_type_ok(mod->symtab[i].st_info)) {
- sm->symbols[num].symbol = dataptr;
- sm->symbols[num].addr = mod->symtab[i].st_value;
- while (*str && (dataptr < endptr))
- *dataptr++ = *str++;
- if (unlikely(*str))
- overflow = 1;
- *dataptr++ = 0;
- num++;
- }
- }
- if (unlikely(overflow))
- errk("Symbol names truncated!!! Should never happen!!\n");
-
- /* sort symbols by address */
- _stp_sort(sm->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol);
-
- return sm;
-}
-
-/* Remove any old module info from our database. */
-static void _stp_module_exists_delete(struct _stp_module *mod)
-{
- int i, num;
- /* remove any old modules with the same name */
- for (num = 1; num < _stp_num_modules; num++) {
- if (strcmp(_stp_modules[num]->name, mod->name) == 0) {
- dbug_sym(1, "found existing module with name %s. Deleting.\n", mod->name);
- _stp_del_module(_stp_modules[num]);
- break;
- }
- }
-
- /* remove modules with overlapping addresses */
- for (num = 1; num < _stp_num_modules; num++) {
- if (mod->text + mod->text_size < _stp_modules_by_addr[num]->text)
- continue;
- if (mod->text < _stp_modules_by_addr[num]->text + _stp_modules_by_addr[num]->text_size) {
- dbug_sym(1, "New module %s overlaps with old module %s. Deleting old.\n",
- mod->name, _stp_modules_by_addr[num]->name);
- _stp_del_module(_stp_modules_by_addr[num]);
- }
- }
-
-}
-
-static void _stp_ins_module(struct module *mod)
-{
- int i, num, res;
- unsigned long flags;
- struct _stp_module *m;
- dbug_sym(1, "insert %s\n", mod->name);
- m = _stp_load_module_symbols(mod);
- if (m == NULL)
- return;
-
- STP_WLOCK_MODULES;
- _stp_module_exists_delete(m);
- /* check for overflow */
- if (_stp_num_modules == STP_MAX_MODULES) {
- errk("Exceeded the limit of %d modules\n", STP_MAX_MODULES);
- goto done;
- }
-
- /* insert alphabetically in _stp_modules[] */
- for (num = 1; num < _stp_num_modules; num++)
- if (strcmp(_stp_modules[num]->name, m->name) > 0)
- break;
- for (i = _stp_num_modules; i > num; i--)
- _stp_modules[i] = _stp_modules[i - 1];
- _stp_modules[num] = m;
- /* insert by text address in _stp_modules_by_addr[] */
- for (num = 1; num < _stp_num_modules; num++)
- if (m->text < _stp_modules_by_addr[num]->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] = m;
- _stp_num_modules++;
-done:
- STP_WUNLOCK_MODULES;
- return;
-}
-
-static int _stp_module_load_notify(struct notifier_block *self, unsigned long val, void *data)
-{
- struct module *mod = (struct module *)data;
- struct _stp_module rmod;
- switch (val) {
- case MODULE_STATE_COMING:
- dbug_sym(1, "module %s load notify\n", mod->name);
- _stp_ins_module(mod);
- break;
- default:
- errk("module loaded? val=%ld\n", val);
- }
- return 0;
-}
-
-static struct notifier_block _stp_module_load_nb = {
- .notifier_call = _stp_module_load_notify,
-};
-
-#include <linux/seq_file.h>
-
-static int _stp_init_modules(void)
-{
- loff_t pos = 0;
- void *res;
- struct module *mod;
- const struct seq_operations *modules_op = (const struct seq_operations *)_stp_kallsyms_lookup_name("modules_op");
-
- if (modules_op == NULL) {
- _dbug("Lookup of modules_op failed.\n");
- return -1;
- }
-
- /* Use the seq_file interface to safely get a list of installed modules */
- res = modules_op->start(NULL, &pos);
- while (res) {
- mod = list_entry(res, struct module, list);
- _stp_ins_module(mod);
- res = modules_op->next(NULL, res, &pos);
- }
-
- if (register_module_notifier(&_stp_module_load_nb))
- errk("failed to load module notifier\n");
-
- /* unlocks the list */
- modules_op->stop(NULL, NULL);
-
-#if 0 /* def STP_USE_DWARF_UNWINDER */
- /* now that we have all the modules, ask for their unwind info */
- {
- unsigned long flags;
- int i, left = STP_CTL_BUFFER_SIZE;
- char buf[STP_CTL_BUFFER_SIZE];
- char *ptr = buf;
- *ptr = 0;
-
- STP_RLOCK_MODULES;
- /* Loop through modules, sending module names packed into */
- /* messages of size STP_CTL_BUFFER. */
- for (i = 0; i < _stp_num_modules; i++) {
- char *name = _stp_modules[i]->name;
- int len = strlen(name);
- if (len >= left) {
- _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left);
- ptr = buf;
- left = STP_CTL_BUFFER_SIZE;
- }
- strlcpy(ptr, name, left);
- ptr += len + 1;
- left -= len + 1;
- }
- STP_RUNLOCK_MODULES;
-
- /* Send terminator. When we get this back from stapio */
- /* that means all the unwind info has been sent. */
- strlcpy(ptr, "*", left);
- left -= 2;
- _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left);
- }
-#else
- /* done with modules, now go */
- _stp_ctl_send(STP_TRANSPORT, NULL, 0);
-#endif /* STP_USE_DWARF_UNWINDER */
-
- return 0;
-}
#endif /* _STP_SYMBOLS_C_ */
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index c6ca4c62..01a24033 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -84,7 +84,6 @@ static void _stp_cleanup_and_exit(int send_exit)
int failures;
_stp_exit_flag = 1;
- unregister_module_notifier(&_stp_module_load_nb);
/* we only want to do this stuff once */
_stp_exit_called = 1;
@@ -180,8 +179,7 @@ void _stp_transport_close()
_stp_unregister_ctl_channel();
if (_stp_utt)
utt_trace_remove(_stp_utt);
- _stp_free_modules();
- _stp_kill_time();
+ _stp_kill_time(); /* Go to a beach. Drink a beer. */
_stp_print_cleanup(); /* free print buffers */
_stp_mem_debug_done();
dbug_trans(1, "---- CLOSED ----\n");
@@ -263,25 +261,11 @@ int _stp_transport_init(void)
_stp_transport_state = 1;
- dbug_trans(1, "calling init_kernel_symbols\n");
- if (_stp_init_kernel_symbols() < 0)
- goto err4;
-
- /*
- dbug_trans(1, "calling init_modules\n");
- if (_stp_init_modules() < 0)
- goto err4;
- */
-
/* Signal stapio to send us STP_START back (XXX: ?!?!?!). */
_stp_ctl_send(STP_TRANSPORT, NULL, 0);
return 0;
-err4:
- errk("failed to initialize modules\n");
- _stp_free_modules();
- destroy_workqueue(_stp_wq);
err3:
_stp_print_cleanup();
err2:
diff --git a/runtime/unwind.c b/runtime/unwind.c
index aa270cad..21ea4559 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -108,7 +108,6 @@ static void _stp_create_unwind_hdr(struct _stp_module *m)
header = _stp_vmalloc(hdrSize);
if (header == NULL)
return;
- m->allocated.unwind_hdr = 1;
}
header->version = 1;
@@ -156,17 +155,10 @@ static void _stp_create_unwind_hdr(struct _stp_module *m)
bad:
dbug_unwind(1, "unwind data for %s is unacceptable. Freeing.", m->name);
if (header) {
- if (m->allocated.unwind_hdr) {
- m->allocated.unwind_hdr = 0;
- _stp_vfree(header);
- } else
- _stp_kfree(header);
+ _stp_vfree(header);
}
if (m->unwind_data) {
- if (m->allocated.unwind_data)
- _stp_vfree(m->unwind_data);
- else
- _stp_kfree(m->unwind_data);
+ _stp_vfree(m->unwind_data);
m->unwind_data = NULL;
m->unwind_data_len = 0;
}
@@ -691,7 +683,7 @@ int unwind(struct unwind_frame_info *frame)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_get_unwind_info(pc);
+ m = NULL /*_stp_get_unwind_info(pc) */;
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
@@ -940,21 +932,18 @@ int unwind(struct unwind_frame_info *frame)
break;
}
}
- read_unlock(&m->lock);
dbug_unwind(1, "returning 0 (%lx)\n", UNW_PC(frame));
return 0;
copy_failed:
dbug_unwind(1, "_stp_read_address failed to access memory\n");
err:
- read_unlock(&m->lock);
return -EIO;
done:
/* PC was in a range convered by a module but no unwind info */
/* found for the specific PC. This seems to happen only for kretprobe */
/* trampolines and at the end of interrupt backtraces. */
- read_unlock(&m->lock);
return 1;
#undef CASES
#undef FRAME_REG
diff --git a/translate.cxx b/translate.cxx
index e5c91a3b..d878cfd7 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -22,6 +22,7 @@
#include <sstream>
#include <string>
#include <cassert>
+#include <cstring>
extern "C" {
#include <elfutils/libdwfl.h>
@@ -4331,6 +4332,7 @@ struct unwindsym_dump_context
{
systemtap_session& session;
ostream& output;
+ unsigned stp_module_index;
};
@@ -4343,6 +4345,7 @@ dump_unwindsyms (Dwfl_Module *m,
{
unwindsym_dump_context* c = (unwindsym_dump_context*) arg;
assert (c);
+ unsigned real_stpmodules_index = c->stp_module_index;
string modname = name;
@@ -4350,53 +4353,138 @@ dump_unwindsyms (Dwfl_Module *m,
if (c->session.unwindsym_modules.find(modname) == c->session.unwindsym_modules.end())
return DWARF_CB_OK;
+ c->stp_module_index ++;
+
if (c->session.verbose > 1)
- clog << "dump_unwindsyms " << name << " base=0x" << hex << base << dec << endl;
+ clog << "dump_unwindsyms " << name
+ << " index=" << real_stpmodules_index
+ << " base=0x" << hex << base << dec << endl;
// We want to extract several bits of information:
// - parts of the program-header that map the file's physical offsets to the text section
- // - symbol table of the text section
- // - the contents .debug_frame section
+ // - section table: just a list of section (relocation) base addresses
+ // - symbol table of the text section, with all addresses relativized to .text base
+ // - the contents of .debug_frame section, for unwinding purposes
// In the future, we'll also care about data symbols.
+ c->output << "struct _stp_symbol _stp_module_" << real_stpmodules_index<< "_sections[] = {" << endl;
+ if (modname != "kernel")
+ c->output << " { 0, \".text\" }, " << endl; // XXX
+ else
+ c->output << " { 0, \"_stext\" }, " << endl; // XXX
+ c->output << "};" << endl;
+
int syments = dwfl_module_getsymtab(m);
assert(syments);
- c->output << "struct _stp_symbol _stp_kernel_symbols[] = {" << endl;
+ // Look up the relocation basis for symbols
+ int n = dwfl_module_relocations (m);
+ dwfl_assert ("dwfl_module_relocations", n >= 0);
+
+ // XXX: unfortunate duplication with tapsets.cxx:emit_address()
+
+ typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address
+ addrmap_t addrmap; // NB: plain map, sorted by address
+
+ Dwarf_Addr extra_offset = 0;
+
for (int i = 1; i < syments; ++i)
{
GElf_Sym sym;
const char *name = dwfl_module_getsym(m, i, &sym, NULL);
if (name)
{
+ // NB: Yey, we found the kernel's _stext value.
+ // Sess.sym_stext may be unset (0) at this point, since
+ // there may have been no kernel probes set. We could
+ // use tapsets.cxx:lookup_symbol_address(), but then
+ // we're already iterating over the same data here...
+ if (modname == "kernel" && !strcmp(name, "_stext"))
+ {
+ extra_offset = sym.st_value;
+ if (c->session.verbose > 2)
+ clog << "Found kernel _stext 0x" << hex << extra_offset << dec << endl;
+ }
+
if (GELF_ST_TYPE (sym.st_info) == STT_FUNC)
{
- if (sym.st_value < c->session.sym_stext) continue;
+ Dwarf_Addr sym_addr = sym.st_value;
+
+ int i = dwfl_module_relocate_address (m, &sym_addr);
+ dwfl_assert ("dwfl_module_relocate_address", i >= 0);
+ const char *secname = dwfl_module_relocation_info (m, i, NULL);
+
+ if (n == 0 || (n==1 && secname == NULL))
+ {
+ if (c->session.verbose > 2)
+ clog << "Skipped absolute symbol " << name << endl;
+ continue;
+ }
+
+ if (n == 1 && modname == "kernel" && secname[0] == '\0')
+ {
+ // This is a symbol within a relocatable kernel image.
+ secname = "_stext"; // not actually used
+ // NB: don't subtract session.sym_stext, which could be inconveniently NULL.
+ }
+ else if (strcmp (secname, ".text")) /* XXX: only care about .text-related relocations for now. */
+ {
+ if (c->session.verbose > 2)
+ clog << "Skipped symbol " << name << ", due to non-.text relocation section " << secname << endl;
+ continue;
+ }
+ else
+ {
+ // sym_addr has already been relocate relative to .text
+ }
- c->output << " { 0x" << hex
- << sym.st_value - c->session.sym_stext /* <<---- note _stext subtraction */
- << dec
- << ", " << lex_cast_qstring (name) << " }," << endl;
+ addrmap[sym_addr] = name;
}
}
}
+
+ // We write out a *sorted* symbol table, so the runtime doesn't have to sort them later.
+ c->output << "struct _stp_symbol _stp_module_" << real_stpmodules_index<< "_symbols[] = {" << endl;
+ for (addrmap_t::iterator it = addrmap.begin(); it != addrmap.end(); it++)
+ {
+ if (it->first < extra_offset)
+ continue; // skip symbols that occur before our chosen base address
+
+ c->output << " { 0x" << hex << it->first-extra_offset << dec
+ << ", " << lex_cast_qstring (it->second) << " }," << endl;
+ }
c->output << "};" << endl;
- c->output << "unsigned _stp_num_kernel_symbols = "
- << "sizeof (_stp_kernel_symbols)/sizeof(struct _stp_symbol);" << endl;
+
+ c->output << "struct _stp_module _stp_module_" << real_stpmodules_index << " = {" << endl;
+ c->output << ".name = " << lex_cast_qstring (modname) << ", " << endl;
+
+ c->output << ".sections = _stp_module_" << real_stpmodules_index << "_sections" << ", " << endl;
+ c->output << ".num_sections = sizeof(_stp_module_" << real_stpmodules_index << "_sections)/"
+ << "sizeof(struct _stp_symbol), " << endl;
+
+ c->output << ".symbols = _stp_module_" << real_stpmodules_index << "_symbols" << ", " << endl;
+ c->output << ".num_symbols = sizeof(_stp_module_" << real_stpmodules_index << "_symbols)/"
+ << "sizeof(struct _stp_symbol), " << endl;
+
+ c->output << "};" << endl << endl;
return DWARF_CB_OK;
}
+// Emit symbol table & unwind data, plus any calls needed to register
+// them with the runtime.
+
void
emit_symbol_data (systemtap_session& s)
{
string symfile = "stap-symbols.h";
- ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str());
- unwindsym_dump_context ctx = { s, kallsyms_out };
+ s.op->newline() << "#include " << lex_cast_qstring (symfile);
+
+ ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str());
- s.op->newline() << "\n\n#include \"" << symfile << "\"";
+ unwindsym_dump_context ctx = { s, kallsyms_out, 0 };
// XXX: copied from tapsets.cxx, sadly
static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build";
@@ -4450,7 +4538,6 @@ emit_symbol_data (systemtap_session& s)
string modname = *it;
assert (modname.length() != 0);
if (modname[0] != '/') continue; // user-space files must be full paths
-
Dwfl *dwfl = dwfl_begin (&user_callbacks);
if (!dwfl)
throw semantic_error ("cannot create dwfl for " + modname);
@@ -4469,6 +4556,18 @@ emit_symbol_data (systemtap_session& s)
dwfl_assert("dwfl_getmodules", off == 0);
dwfl_end(dwfl);
}
+
+
+ // Print out a definition of the runtime's _stp_modules[] globals.
+
+ kallsyms_out << endl;
+ kallsyms_out << "struct _stp_module *_stp_modules [] = {" << endl;
+ for (unsigned i=0; i<ctx.stp_module_index; i++)
+ {
+ kallsyms_out << "& _stp_module_" << i << "," << endl;
+ }
+ kallsyms_out << "};" << endl;
+ kallsyms_out << "int _stp_num_modules = " << ctx.stp_module_index << ";" << endl;
}