summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buildrun.cxx2
-rw-r--r--runtime/autoconf-asm-syscall.c2
-rw-r--r--runtime/syscall.h298
-rw-r--r--runtime/task_finder.c56
-rw-r--r--tapset/utrace.stp8
5 files changed, 214 insertions, 152 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index bcd4c1fe..82ac9d4e 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -165,6 +165,8 @@ compile_pass (systemtap_session& s)
#endif
output_autoconf(s, o, "autoconf-save-stack-trace.c",
"STAPCONF_KERNEL_STACKTRACE", NULL);
+ output_autoconf(s, o, "autoconf-asm-syscall.c",
+ "STAPCONF_ASM_SYSCALL_H", NULL);
o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
diff --git a/runtime/autoconf-asm-syscall.c b/runtime/autoconf-asm-syscall.c
new file mode 100644
index 00000000..bf7a273f
--- /dev/null
+++ b/runtime/autoconf-asm-syscall.c
@@ -0,0 +1,2 @@
+#include <asm/syscall.h>
+
diff --git a/runtime/syscall.h b/runtime/syscall.h
index ae451070..6d22ba83 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -1,5 +1,6 @@
-/* syscall defines and inlines
- * Copyright (C) 2008 Red Hat Inc.
+/*
+ * syscall defines and inlines
+ * Copyright (C) 2008-2009 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
@@ -89,9 +90,17 @@
#error "Unimplemented architecture"
#endif
+#ifdef STAPCONF_ASM_SYSCALL_H
+
+/* If the system has asm/syscall.h, use defines from it. */
+#include <asm/syscall.h>
+
+#else /* !STAPCONF_ASM_SYSCALL_H */
+
+/* If the system doesn't have asm/syscall.h, use our defines. */
#if defined(__i386__) || defined(__x86_64__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
#if defined(STAPCONF_X86_UNIREGS)
return regs->orig_ax;
@@ -104,37 +113,37 @@ __stp_user_syscall_nr(struct pt_regs *regs)
#endif
#if defined(__powerpc__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
return regs->gpr[0];
}
#endif
#if defined(__ia64__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
return regs->r15;
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
- // might need to be 'orig_gpr2'
+ // might need to be 'orig_gpr2'
return regs->gprs[2];
}
#endif
#if defined(__i386__) || defined(__x86_64__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
#ifdef CONFIG_IA32_EMULATION
// This code works, but isn't what we need. Since
-// __stp_user_syscall_arg() doesn't sign-extend, a value passed in as
+// syscall_get_syscall_arg() doesn't sign-extend, a value passed in as
// an argument and then returned won't compare correctly anymore. So,
// for now, disable this code.
# if 0
@@ -145,158 +154,233 @@ __stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
# endif
#endif
#if defined(STAPCONF_X86_UNIREGS)
- return &regs->ax;
+ return regs->ax;
#elif defined(__x86_64__)
- return &regs->rax;
+ return regs->rax;
#elif defined (__i386__)
- return &regs->eax;
+ return regs->eax;
#endif
}
#endif
#if defined(__powerpc__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->gpr[3];
+ return regs->gpr[3];
}
#endif
#if defined(__ia64__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->r8;
+ return regs->r8;
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->gprs[2];
+ return regs->gprs[2];
}
#endif
#if defined(__i386__) || defined(__x86_64__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
-#if defined(__i386__)
- if (n > 5) {
- _stp_error("syscall arg > 5");
- return NULL;
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
}
+#if defined(__i386__)
#if defined(STAPCONF_X86_UNIREGS)
- return &regs->bx + n;
+ memcpy(args, &regs->bx + i, n * sizeof(args[0]));
#else
- return &regs->ebx + n;
+ memcpy(args, &regs->ebx + i, n * sizeof(args[0]));
#endif
#elif defined(__x86_64__)
#ifdef CONFIG_IA32_EMULATION
- if (test_tsk_thread_flag(task, TIF_IA32))
- switch (n) {
+ if (test_tsk_thread_flag(task, TIF_IA32)) {
+ switch (i) {
#if defined(STAPCONF_X86_UNIREGS)
- case 0: return &regs->bx;
- case 1: return &regs->cx;
- case 2: return &regs->dx;
- case 3: return &regs->si;
- case 4: return &regs->di;
- case 5: return &regs->bp;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->bx;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->cx;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->dx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->si;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->di;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->bp;
#else
- case 0: return &regs->rbx;
- case 1: return &regs->rcx;
- case 2: return &regs->rdx;
- case 3: return &regs->rsi;
- case 4: return &regs->rdi;
- case 5: return &regs->rbp;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->rbx;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->rcx;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->rdx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->rsi;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->rdi;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->rbp;
#endif
- default:
- _stp_error("syscall arg > 5");
- return NULL;
}
+ return;
+ }
#endif /* CONFIG_IA32_EMULATION */
- switch (n) {
+ switch (i) {
#if defined(STAPCONF_X86_UNIREGS)
- case 0: return &regs->di;
- case 1: return &regs->si;
- case 2: return &regs->dx;
- case 3: return &regs->r10;
- case 4: return &regs->r8;
- case 5: return &regs->r9;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->di;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->si;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->dx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->r10;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->r8;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->r9;
#else
- case 0: return &regs->rdi;
- case 1: return &regs->rsi;
- case 2: return &regs->rdx;
- case 3: return &regs->r10;
- case 4: return &regs->r8;
- case 5: return &regs->r9;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->rdi;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->rsi;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->rdx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->r10;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->r8;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->r9;
#endif
- default:
- _stp_error("syscall arg > 5");
- return NULL;
}
#endif /* CONFIG_X86_32 */
+ return;
}
#endif
#if defined(__powerpc__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
- switch (n) {
- case 0: return &regs->gpr[3];
- case 1: return &regs->gpr[4];
- case 2: return &regs->gpr[5];
- case 3: return &regs->gpr[6];
- case 4: return &regs->gpr[7];
- case 5: return &regs->gpr[8];
- default:
- _stp_error("syscall arg > 5");
- return NULL;
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
}
+ memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
}
#endif
#if defined(__ia64__)
-#define __stp_user_syscall_arg(task, regs, n) \
- ____stp_user_syscall_arg(task, regs, n, &c->unwaddr)
+#define syscall_get_arguments(task, regs, i, n, args) \
+ __ia64_syscall_get_arguments(task, regs, i, n, args, &c->unwaddr)
-static inline long *
-____stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n, unsigned long **cache)
+static inline void
+__ia64_syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args, unsigned long **cache)
{
- if (n > 5) {
- _stp_error("syscall arg > 5");
- return NULL;
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
+ }
+ switch (i) {
+ case 0:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 32, regs, cache);
+ case 1:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 33, regs, cache);
+ case 2:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 34, regs, cache);
+ case 3:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 35, regs, cache);
+ case 4:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 36, regs, cache);
+ case 5:
+ if (!n--) break;
+ *args++ = *__ia64_fetch_register(i + 37, regs, cache);
}
- return __ia64_fetch_register(n + 32, regs, cache);
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
- /* If we were returning a value, we could check for TIF_31BIT
- * here and cast the value with '(u32)' to make sure it got
- * down to 32bits. But, since we're returning an address,
- * there isn't much we can do. */
- switch (n) {
- case 0: return &regs->orig_gpr2;
- case 1: return &regs->gprs[3];
- case 2: return &regs->gprs[4];
- case 3: return &regs->gprs[5];
- case 4: return &regs->gprs[6];
- case 5: return &regs->args[0];
- default:
- _stp_error("syscall arg > 5");
- return NULL;
+ unsigned long mask = -1UL;
+
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
+ }
+#ifdef CONFIG_COMPAT
+ if (test_tsk_thread_flag(task, TIF_31BIT))
+ mask = 0xffffffff;
+#endif
+ switch (i) {
+ case 0:
+ if (!n--) break;
+ *args++ = regs->orig_gpr2 & mask;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->gprs[3] & mask;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->gprs[4] & mask;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->gprs[5] & mask;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->gprs[6] & mask;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->args[0] & mask;
}
}
#endif
+#endif /* !STAPCONF_ASM_SYSCALL_H */
#endif /* _SYSCALL_H_ */
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 433a042a..fa6c296e 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -1065,11 +1065,9 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
#endif
{
struct stap_task_finder_target *tgt = engine->data;
- unsigned long syscall_no;
- unsigned long *rv_addr, rv;
- unsigned long *arg_addr, arg0;
- unsigned long arg1 = 0;
- unsigned long arg2 = 0;
+ long syscall_no;
+ unsigned long rv;
+ unsigned long args[3];
int rc;
struct mm_struct *mm;
struct vm_area_struct *vma;
@@ -1088,7 +1086,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
// See if syscall is one we're interested in.
//
// FIXME: do we need to handle mremap()?
- syscall_no = __stp_user_syscall_nr(regs);
+ syscall_no = syscall_get_nr(tsk, regs);
if (syscall_no != MMAP_SYSCALL_NO(tsk)
&& syscall_no != MMAP2_SYSCALL_NO(tsk)
&& syscall_no != MPROTECT_SYSCALL_NO(tsk)
@@ -1106,21 +1104,11 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
return UTRACE_RESUME;
// Get return value
- rv_addr = __stp_user_syscall_return_value(tsk, regs);
- if ((rc = __stp_get_user(rv, rv_addr)) != 0) {
- _stp_error("couldn't read syscall return value for pid %d: %d",
- tsk->pid, rc);
- return UTRACE_RESUME;
- }
+ rv = syscall_get_return_value(tsk, regs);
// We need the first syscall argument to see what address we
// were operating on.
- arg_addr = __stp_user_syscall_arg(tsk, regs, 0);
- if ((rc = __stp_get_user(arg0, arg_addr)) != 0) {
- _stp_error("couldn't read syscall arg 0 for pid %d: %d",
- tsk->pid, rc);
- return UTRACE_RESUME;
- }
+ syscall_get_arguments(tsk, regs, 0, 1, args);
#ifdef DEBUG_TASK_FINDER_VMA
_stp_dbug(__FUNCTION__, __LINE__,
@@ -1131,20 +1119,15 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
: ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect"
: ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap"
: "UNKNOWN")))),
- arg0, rv);
+ args[0], rv);
#endif
__stp_tf_handler_start();
if (syscall_no == MUNMAP_SYSCALL_NO(tsk)) {
// We need the 2nd syscall argument for the length.
- arg_addr = __stp_user_syscall_arg(tsk, regs, 1);
- if ((rc = __stp_get_user(arg1, arg_addr)) != 0) {
- _stp_error("couldn't read syscall arg 1 for pid %d: %d",
- tsk->pid, rc);
- goto syscall_exit_done;
- }
+ syscall_get_arguments(tsk, regs, 1, 1, &args[1]);
// Call the callbacks
- __stp_call_munmap_callbacks(tgt, tsk, arg0, arg1);
+ __stp_call_munmap_callbacks(tgt, tsk, args[0], args[1]);
}
else if (syscall_no == MMAP_SYSCALL_NO(tsk)
|| syscall_no == MMAP2_SYSCALL_NO(tsk)) {
@@ -1165,24 +1148,13 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
}
}
else {
- // We need the 2nd syscall argument for the length.
- arg_addr = __stp_user_syscall_arg(tsk, regs, 1);
- if ((rc = __stp_get_user(arg1, arg_addr)) != 0) {
- _stp_error("couldn't read syscall arg 1 for pid %d: %d",
- tsk->pid, rc);
- goto syscall_exit_done;
- }
-
- // We need the 3nd syscall argument for the protection.
- arg_addr = __stp_user_syscall_arg(tsk, regs, 2);
- if ((rc = __stp_get_user(arg2, arg_addr)) != 0) {
- _stp_error("couldn't read syscall arg 2 for pid %d: %d",
- tsk->pid, rc);
- goto syscall_exit_done;
- }
+ // We need the 2nd syscall argument for the length and
+ // the 3rd argument for the protection.
+ syscall_get_arguments(tsk, regs, 1, 2, &args[1]);
// Call the callbacks
- __stp_call_mprotect_callbacks(tgt, tsk, arg0, arg1, arg2);
+ __stp_call_mprotect_callbacks(tgt, tsk, args[0], args[1],
+ args[2]);
}
syscall_exit_done:
diff --git a/tapset/utrace.stp b/tapset/utrace.stp
index 34cb32c5..00f427e6 100644
--- a/tapset/utrace.stp
+++ b/tapset/utrace.stp
@@ -6,13 +6,15 @@
%}
function _utrace_syscall_nr:long () %{
- THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */
+ THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs); /* pure */
%}
function _utrace_syscall_arg:long (n:long) %{
- THIS->__retvalue = *__stp_user_syscall_arg(current, CONTEXT->regs, (int)THIS->n); /* pure */
+ unsigned long arg = 0; /* pure */
+ syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg);
+ THIS->__retvalue = arg;
%}
function _utrace_syscall_return:long () %{
- THIS->__retvalue = *__stp_user_syscall_return_value(current, CONTEXT->regs); /* pure */
+ THIS->__retvalue = syscall_get_return_value(current, CONTEXT->regs); /* pure */
%}