new file mode 100644
@@ -0,0 +1,28 @@
+#ifndef _KALLSYMS_WRAPPER_H
+#define _KALLSYMS_WRAPPER_H
+
+/*
+ * Copyright (C) 2011 Avik Sil (avik.sil at linaro.org)
+ *
+ * wrapper around kallsyms_lookup_name. Implements arch-dependent code for
+ * arches where the address of the start of the function body is different
+ * from the pointer which can be used to call the function, e.g. ARM THUMB2.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+*/
+
+static inline
+unsigned long kallsyms_lookup_funcptr(const char *name)
+{
+ unsigned long addr;
+
+ addr = kallsyms_lookup_name(name);
+#ifdef CONFIG_ARM
+#ifdef CONFIG_THUMB2_KERNEL
+ if (addr)
+ addr |= 1; /* set bit 0 in address for thumb mode */
+#endif
+#endif
+ return addr;
+}
+#endif /* _KALLSYMS_WRAPPER_H */
@@ -190,6 +190,8 @@ static void *kallsyms_signal_wake_up;
static void *kallsyms___lock_task_sighand;
#endif
+#include "kallsyms_wrapper.h"
+
#include "access_process_vm.h"
#include "loc2c-runtime.h"
@@ -25,12 +25,12 @@ stp_task_work_init(void)
#if !defined(STAPCONF_TASK_WORK_ADD_EXPORTED)
/* The task_work_add()/task_work_cancel() functions aren't
* exported. Look up those function addresses. */
- kallsyms_task_work_add = (void *)kallsyms_lookup_name("task_work_add");
+ kallsyms_task_work_add = (void *)kallsyms_lookup_funcptr("task_work_add");
if (kallsyms_task_work_add == NULL) {
_stp_error("Can't resolve task_work_add!");
return -ENOENT;
}
- kallsyms_task_work_cancel = (void *)kallsyms_lookup_name("task_work_cancel");
+ kallsyms_task_work_cancel = (void *)kallsyms_lookup_funcptr("task_work_cancel");
if (kallsyms_task_work_cancel == NULL) {
_stp_error("Can't resolve task_work_cancel!");
return -ENOENT;
@@ -191,12 +191,12 @@ static int utrace_init(void)
/* The signal_wake_up_state() function (which replaces
* signal_wake_up() in newer kernels) isn't exported. Look up
* that function address. */
- kallsyms_signal_wake_up_state = (void *)kallsyms_lookup_name("signal_wake_up_state");
+ kallsyms_signal_wake_up_state = (void *)kallsyms_lookup_funcptr("signal_wake_up_state");
#endif
#if !defined(STAPCONF_SIGNAL_WAKE_UP_EXPORTED)
/* The signal_wake_up() function isn't exported. Look up that
* function address. */
- kallsyms_signal_wake_up = (void *)kallsyms_lookup_name("signal_wake_up");
+ kallsyms_signal_wake_up = (void *)kallsyms_lookup_funcptr("signal_wake_up");
#endif
#if (!defined(STAPCONF_SIGNAL_WAKE_UP_STATE_EXPORTED) \
&& !defined(STAPCONF_SIGNAL_WAKE_UP_EXPORTED))
@@ -209,7 +209,7 @@ static int utrace_init(void)
#if !defined(STAPCONF___LOCK_TASK_SIGHAND_EXPORTED)
/* The __lock_task_sighand() function isn't exported. Look up
* that function address. */
- kallsyms___lock_task_sighand = (void *)kallsyms_lookup_name("__lock_task_sighand");
+ kallsyms___lock_task_sighand = (void *)kallsyms_lookup_funcptr("__lock_task_sighand");
if (kallsyms___lock_task_sighand == NULL) {
_stp_error("Can't resolve __lock_task_sighand!");
goto error;
@@ -352,7 +352,7 @@ static int _stp_transport_init(void)
/* PR13489, missing inode-uprobes symbol-export workaround */
#if !defined(STAPCONF_TASK_USER_REGSET_VIEW_EXPORTED) && !defined(STAPCONF_UTRACE_REGSET) /* RHEL5 era utrace */
- kallsyms_task_user_regset_view = (void*) kallsyms_lookup_name ("task_user_regset_view");
+ kallsyms_task_user_regset_view = (void*) kallsyms_lookup_funcptr ("task_user_regset_view");
/* There exist interesting kernel versions without task_user_regset_view(), like ARM before 3.0.
For these kernels, uprobes etc. are out of the question, but plain kernel stap works fine.
All we have to accomplish is have the loc2c runtime code compile. For that, it's enough
@@ -363,9 +363,9 @@ static int _stp_transport_init(void)
#endif
#if defined(CONFIG_UPROBES) // i.e., kernel-embedded uprobes
#if !defined(STAPCONF_UPROBE_REGISTER_EXPORTED)
- kallsyms_uprobe_register = (void*) kallsyms_lookup_name ("uprobe_register");
+ kallsyms_uprobe_register = (void*) kallsyms_lookup_funcptr ("uprobe_register");
if (kallsyms_uprobe_register == NULL) {
- kallsyms_uprobe_register = (void*) kallsyms_lookup_name ("register_uprobe");
+ kallsyms_uprobe_register = (void*) kallsyms_lookup_funcptr ("register_uprobe");
}
if (kallsyms_uprobe_register == NULL) {
printk(KERN_ERR "%s can't resolve uprobe_register!", THIS_MODULE->name);
@@ -373,9 +373,9 @@ static int _stp_transport_init(void)
}
#endif
#if !defined(STAPCONF_UPROBE_UNREGISTER_EXPORTED)
- kallsyms_uprobe_unregister = (void*) kallsyms_lookup_name ("uprobe_unregister");
+ kallsyms_uprobe_unregister = (void*) kallsyms_lookup_funcptr ("uprobe_unregister");
if (kallsyms_uprobe_unregister == NULL) {
- kallsyms_uprobe_unregister = (void*) kallsyms_lookup_name ("unregister_uprobe");
+ kallsyms_uprobe_unregister = (void*) kallsyms_lookup_funcptr ("unregister_uprobe");
}
if (kallsyms_uprobe_unregister == NULL) {
printk(KERN_ERR "%s can't resolve uprobe_unregister!", THIS_MODULE->name);
@@ -383,7 +383,7 @@ static int _stp_transport_init(void)
}
#endif
#if !defined(STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED)
- kallsyms_uprobe_get_swbp_addr = (void*) kallsyms_lookup_name ("uprobe_get_swbp_addr");
+ kallsyms_uprobe_get_swbp_addr = (void*) kallsyms_lookup_funcptr ("uprobe_get_swbp_addr");
if (kallsyms_uprobe_get_swbp_addr == NULL) {
printk(KERN_ERR "%s can't resolve uprobe_get_swbp_addr!", THIS_MODULE->name);
goto err0;
Thumb2 function pointer should have bit 0 set when called, even if function text is aligned with 2 or 4 bytes. Current systemtap runtime uses kallsyms_lookup_name to get function pointer, cast it, and calls it. It does not work in case of arm CONFIG_THUMB2_KERNEL. The patch add simple wrapper on top of kallsyms_lookup_name, which in case of CONFIG_THUMB2_KERNEL set bit 0 of returned function address. In all other case it just returns result of kallsyms_lookup_name call. In case if/when kernel will provide similar to kallsyms_lookup_funcptr functionality in kernel itself remove/rework this change. Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org> --- runtime/linux/kallsyms_wrapper.h | 28 ++++++++++++++++++++++++++++ runtime/linux/runtime.h | 2 ++ runtime/stp_task_work.c | 4 ++-- runtime/stp_utrace.c | 6 +++--- runtime/transport/transport.c | 12 ++++++------ 5 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 runtime/linux/kallsyms_wrapper.h