summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@elastic.org>2008-06-29 10:14:19 -0400
committerFrank Ch. Eigler <fche@elastic.org>2008-06-29 10:14:19 -0400
commit37ddf6e5fa1530adc3a7236379a3a88dfef33d53 (patch)
treead7c05df8b0ebeafa75cfee1ed569bf2722091e2
parent53ca410a6a6032c2cde6aac6e95b57c68585e48a (diff)
downloadsystemtap-steved-37ddf6e5fa1530adc3a7236379a3a88dfef33d53.tar.gz
systemtap-steved-37ddf6e5fa1530adc3a7236379a3a88dfef33d53.tar.xz
systemtap-steved-37ddf6e5fa1530adc3a7236379a3a88dfef33d53.zip
STP_RELOCATE message for kernel relocatability (re)adaption, starting implementation
-rw-r--r--runtime/staprun/common.c25
-rw-r--r--runtime/staprun/mainloop.c23
-rw-r--r--runtime/staprun/staprun.c102
-rw-r--r--runtime/staprun/staprun.h1
-rw-r--r--runtime/sym.c11
-rw-r--r--runtime/transport/control.c7
-rw-r--r--runtime/transport/symbols.c63
-rw-r--r--runtime/transport/transport.c3
-rw-r--r--runtime/transport/transport_msgs.h11
-rw-r--r--translate.cxx15
10 files changed, 210 insertions, 51 deletions
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index 93da51d8..dca45e4d 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -314,3 +314,28 @@ err:
close(fd);
return -1;
}
+
+
+/**
+ * send_request - send request to kernel over control channel
+ * @type: the relay-app command id
+ * @data: pointer to the data to be sent
+ * @len: length of the data to be sent
+ *
+ * Returns 0 on success, negative otherwise.
+ * XXX: no, it doesn't ... it should return @len on success.
+ */
+int send_request(int type, void *data, int len)
+{
+ char buf[1024];
+
+ /* Before doing memcpy, make sure 'buf' is big enough. */
+ if ((len + 4) > (int)sizeof(buf)) {
+ _err("exceeded maximum send_request size.\n");
+ return -1;
+ }
+ memcpy(buf, &type, 4);
+ memcpy(&buf[4], data, len);
+
+ return write(control_channel, buf, len + 4);
+}
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index 2bbadbc9..42037473 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -19,27 +19,6 @@ static int use_old_transport = 0;
//enum _stp_sig_type { sig_none, sig_done, sig_detach };
//static enum _stp_sig_type got_signal = sig_none;
-/**
- * send_request - send request to kernel over control channel
- * @type: the relay-app command id
- * @data: pointer to the data to be sent
- * @len: length of the data to be sent
- *
- * Returns 0 on success, negative otherwise.
- */
-int send_request(int type, void *data, int len)
-{
- char buf[1024];
-
- /* Before doing memcpy, make sure 'buf' is big enough. */
- if ((len + 4) > (int)sizeof(buf)) {
- _err("exceeded maximum send_request size.\n");
- return -1;
- }
- memcpy(buf, &type, 4);
- memcpy(&buf[4], data, len);
- return write(control_channel, buf, len + 4);
-}
static void *signal_thread(void *arg)
{
@@ -308,8 +287,8 @@ int stp_main_loop(void)
setvbuf(ofp, (char *)NULL, _IOLBF, 0);
setup_main_signals();
-
dbug(2, "in main loop\n");
+
send_request(STP_READY, NULL, 0);
/* handle messages from control channel */
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index 0291d01f..daebe705 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -21,12 +21,17 @@
*/
#include "staprun.h"
+#include <sys/uio.h>
+
/* used in dbug, _err and _perr */
char *__name__ = "staprun";
extern long delete_module(const char *, unsigned int);
+int send_relocations ();
+
+
static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
{
pid_t pid;
@@ -206,6 +211,8 @@ int init_staprun(void)
return -1;
if (insert_stap_module() < 0)
return -1;
+ if (send_relocations() < 0)
+ return -1;
}
return 0;
}
@@ -288,3 +295,98 @@ err:
remove_module(modname, 1);
return 1;
}
+
+
+
+/* Send a variety of relocation-related data to the kernel: for the
+ kernel proper, just the "_stext" symbol address; for all loaded
+ modules, a variety of symbol base addresses.
+
+ We do this under protest. The kernel ought expose this data to
+ modules such as ourselves, but instead the upstream community
+ continually shrinks its module-facing interfaces, including this
+ stuff, even when users exist.
+*/
+
+
+void send_a_relocation (const char* module, const char* reloc, unsigned long long address)
+{
+ struct _stp_msg_relocation msg;
+
+ if (strlen(module) >= STP_MODULE_NAME_LEN)
+ { _perr ("module name too long: %s", module); return; }
+ strcpy (msg.module, module);
+
+ if (strlen(reloc) >= STP_SYMBOL_NAME_LEN)
+ { _perr ("reloc name too long: %s", reloc); return; }
+ strcpy (msg.reloc, reloc);
+
+ msg.address = address;
+
+ send_request (STP_RELOCATION, & msg, sizeof (msg));
+ /* XXX: verify send_request RC */
+}
+
+
+int send_relocation_kernel ()
+{
+ FILE* kallsyms = fopen ("/proc/kallsyms", "r");
+ if (kallsyms == NULL)
+ {
+ perror("cannot open /proc/kallsyms");
+ // ... and the kernel module will almost certainly fail to initialize.
+ }
+ else
+ {
+ while (! feof(kallsyms))
+ {
+ char *line = NULL;
+ size_t linesz = 0;
+ ssize_t linesize = getline (& line, & linesz, kallsyms);
+ if (linesize < 0)
+ break;
+ else
+ {
+ unsigned long long address;
+ char type;
+ char* symbol = NULL;
+ int rc = sscanf (line, "%llx %c %as", &address, &type, &symbol);
+ free (line); line=NULL;
+
+#ifdef __powerpc__
+#define KERNEL_RELOC_SYMBOL ".__start"
+#else
+#define KERNEL_RELOC_SYMBOL "_stext"
+#endif
+ if ((rc == 3) && (0 == strcmp(symbol,KERNEL_RELOC_SYMBOL)))
+ {
+ send_a_relocation ("kernel", KERNEL_RELOC_SYMBOL, address);
+
+ /* We need nothing more from the kernel. */
+ fclose (kallsyms);
+ return 0;
+ }
+ if (symbol != NULL) free (symbol);
+ }
+ }
+ fclose (kallsyms);
+ }
+
+ return -1;
+}
+
+
+void send_relocation_modules ()
+{
+ /* XXX */
+}
+
+
+
+int send_relocations ()
+{
+ int rc = send_relocation_kernel ();
+ send_relocation_modules ();
+ return rc;
+}
+
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 60bab391..0a35fee6 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -116,7 +116,6 @@ int init_stapio(void);
int stp_main_loop(void);
int send_request(int type, void *data, int len);
void cleanup_and_exit (int);
-void send_unwind_data(const char *name);
int init_ctl_channel(const char *name, int verb);
void close_ctl_channel(void);
int init_relayfs(void);
diff --git a/runtime/sym.c b/runtime/sym.c
index 7163bf92..eca54a35 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -59,6 +59,8 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
/* 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 {
@@ -88,11 +90,12 @@ 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;
- while (num--) {
- if (strcmp(name, s->symbol) == 0)
- return s->addr;
- s++;
+ for (i=0; i<num; i++, s++) {
+ if (strcmp(name, s->symbol) == 0)
+ return s->addr;
+ s++;
}
return 0;
}
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
index 9319b9ca..b366ccef 100644
--- a/runtime/transport/control.c
+++ b/runtime/transport/control.c
@@ -56,9 +56,10 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz
#else
return -1;
#endif
+ case STP_RELOCATION:
+ _stp_do_relocation (buf, count);
+
case STP_READY:
- /* request symbolic information */
- /* _stp_ask_for_symbols(); */
break;
default:
@@ -66,7 +67,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz
return -EINVAL;
}
- return count;
+ return count; /* Pretend that we absorbed the entire message. */
}
struct _stp_buffer {
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index 9299fc67..cc0a1ce5 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -196,31 +196,54 @@ static int _stp_init_kernel_symbols(void)
_stp_num_modules = 1;
/* Note: this mapping is used by kernel/_stext pseudo-relocations. */
- #ifdef __powerpc__
- _stp_modules[0]->text = _stp_kallsyms_lookup_name(".__start");
- #else
- _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext");
- #endif
- if (_stp_modules[0]->text == 0) {
- _dbug("Lookup of _stext failed. Exiting.\n");
- return -1;
- }
-
- _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext");
- if (_stp_modules[0]->data == 0) {
- _dbug("Lookup of _etext failed. Exiting.\n");
- return -1;
- }
+ _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_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text;
+ _stp_kretprobe_trampoline = 0; /* XXX */
_stp_modules_by_addr[0] = _stp_modules[0];
-
- _stp_kretprobe_trampoline = _stp_kallsyms_lookup_name("kretprobe_trampoline");
- /* Lookup failure is not fatal */
+
+ printk (KERN_INFO "stap kernel data: symbols[%u]=%p\n",
+ _stp_num_kernel_symbols, _stp_kernel_symbols);
return 0;
}
+
+static void _stp_do_relocation(const char __user *buf, size_t count)
+{
+ struct _stp_msg_relocation msg;
+ if (sizeof(msg) != count)
+ {
+ errk ("STP_RELOCATE message size mismatch (%u vs %u)\n", sizeof(msg), count);
+ return;
+ }
+
+ if (unlikely(copy_from_user (& msg, buf, count)))
+ return;
+
+ dbug_sym (1, "STP_RELOCATE (%s %s %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. */
+
+ 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;
@@ -302,6 +325,8 @@ static void _stp_do_unwind_data(const char __user *buf, size_t count)
done:
write_unlock(&m->lock);
}
+#endif /* do_unwind_data; not used */
+
static int _stp_compare_addr(const void *p1, const void *p2)
{
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index a4e4e652..d149dd15 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -267,10 +267,11 @@ int _stp_transport_init(void)
if (_stp_init_kernel_symbols() < 0)
goto err4;
+ /*
dbug_trans(1, "calling init_modules\n");
if (_stp_init_modules() < 0)
goto err4;
-
+ */
return 0;
err4:
diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h
index 27476e76..493c7105 100644
--- a/runtime/transport/transport_msgs.h
+++ b/runtime/transport/transport_msgs.h
@@ -10,6 +10,7 @@
*/
#define STP_MODULE_NAME_LEN 64
+#define STP_SYMBOL_NAME_LEN 64
struct _stp_trace {
uint32_t sequence; /* event number */
@@ -34,6 +35,7 @@ enum
STP_SUBBUFS_CONSUMED,
STP_REALTIME_DATA,
#endif
+ STP_RELOCATION,
STP_MAX_CMD
};
@@ -53,6 +55,7 @@ static const char *_stp_command_name[] = {
"STP_SUBBUFS_CONSUMED",
"STP_REALTIME_DATA",
#endif
+ "STP_RELOCATION",
};
#endif /* DEBUG_TRANS */
@@ -97,3 +100,11 @@ struct _stp_consumed_info
uint32_t consumed;
};
#endif
+
+/* Unwind data. stapio->module */
+struct _stp_msg_relocation
+{
+ char module[STP_MODULE_NAME_LEN];
+ char reloc[STP_SYMBOL_NAME_LEN];
+ uint64_t address;
+};
diff --git a/translate.cxx b/translate.cxx
index 433b82be..e5c91a3b 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -4361,6 +4361,8 @@ dump_unwindsyms (Dwfl_Module *m,
int syments = dwfl_module_getsymtab(m);
assert(syments);
+
+ c->output << "struct _stp_symbol _stp_kernel_symbols[] = {" << endl;
for (int i = 1; i < syments; ++i)
{
GElf_Sym sym;
@@ -4368,9 +4370,20 @@ dump_unwindsyms (Dwfl_Module *m,
if (name)
{
if (GELF_ST_TYPE (sym.st_info) == STT_FUNC)
- ; // addrmap[sym.st_value] = name;
+ {
+ if (sym.st_value < c->session.sym_stext) continue;
+
+ c->output << " { 0x" << hex
+ << sym.st_value - c->session.sym_stext /* <<---- note _stext subtraction */
+ << dec
+ << ", " << lex_cast_qstring (name) << " }," << endl;
+ }
}
}
+ c->output << "};" << endl;
+ c->output << "unsigned _stp_num_kernel_symbols = "
+ << "sizeof (_stp_kernel_symbols)/sizeof(struct _stp_symbol);" << endl;
+
return DWARF_CB_OK;
}