diff options
Diffstat (limited to 'runtime/copy.c')
-rw-r--r-- | runtime/copy.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/runtime/copy.c b/runtime/copy.c new file mode 100644 index 00000000..28880c08 --- /dev/null +++ b/runtime/copy.c @@ -0,0 +1,137 @@ +long _stp_strncpy_from_user(char *dst, const char __user *src, long count); +//static long __stp_strncpy_from_user(char *dst, const char __user *src, long count); + +#if defined (__i386__) +#define __stp_strncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testl %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decl %1\n" \ + " jnz 0b\n" \ + "1: subl %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) +#elif defined (__x86_64__) +#define __stp_strncpy_from_user(dst,src,count,res) \ +do { \ + long __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testq %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decq %1\n" \ + " jnz 0b\n" \ + "1: subq %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movq %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n" \ + " .quad 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) +#endif + +/** Copy a NULL-terminated string from userspace. + * On success, returns the length of the string (not including the trailing + * NULL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * @param dst Destination address, in kernel space. This buffer must be at + * least <i>count</i> bytes long. + * @param src Source address, in user space. + * @param count Maximum number of bytes to copy, including the trailing NULL. + * + * If <i>count</i> is smaller than the length of the string, copies + * <i>count</i> bytes and returns <i>count</i>. + */ + + +long +_stp_strncpy_from_user(char *dst, const char __user *src, long count) +{ + long res; + __stp_strncpy_from_user(dst, src, count, res); + return res; +} + +/** Copy a block of data from user space. + * + * If some data could not be copied, this function will pad the copied + * data to the requested size using zero bytes. + + * @param dst Destination address, in kernel space. + * @param src Source address, in user space. + * @param count Number of bytes to copy. + * @return number of bytes that could not be copied. On success, + * this will be zero. + * + */ + +unsigned long inline +_stp_copy_from_user (char *dst, const char __user *src, unsigned long count) +{ + return __copy_from_user_inatomic(dst, src, count); +} + +/** Copy an argv from user space to a List. + * + * @param list A list. + * @param argv Source argv, in user space. + * @return number of elements in <i>list</i> + * + * @b Example: + * @include argv.c + */ + +int _stp_copy_argv_from_user (MAP list, char __user *__user *argv) +{ + char str[128]; + char __user *vstr; + int len; + + if (argv) + argv++; + + while (argv != NULL) { + if (get_user (vstr, argv)) + break; + + if (vstr == NULL) + break; + + len = _stp_strncpy_from_user(str, vstr, 128); + str[len] = 0; + _stp_list_add_str (list, str); + argv++; + } + return list->num; +} |