From a69fbca6e23aa019e5808be53113d6fa1c83d183 Mon Sep 17 00:00:00 2001 From: Martin Cermak Date: Wed, 13 May 2015 17:06:34 +0200 Subject: [PATCH] PR18398: Tapset support for {get,set}_thread_area syscalls * tapset/linux/i386/aux_syscalls.stp: New function _struct_user_desc_u() * tapset/linux/i386/nd_syscalls.stp: Decode struct user_desc * tapset/linux/i386/syscalls.stp: Ditto * tapset/linux/x86_64/aux_syscalls.stp: New function _struct_user_desc_u() * tapset/linux/x86_64/nd_syscalls.stp: New probes nd_syscall.{get,set}_thread_area * tapset/linux/x86_64/syscalls.stp: New probes syscall.{get,set}_thread_area * testsuite/buildok/nd_syscalls-arch-detailed.stp: New subtests * testsuite/buildok/syscalls-arch-detailed.stp: New subtests * testsuite/systemtap.syscall/thread_area.c: New testcase --- tapset/linux/i386/aux_syscalls.stp | 30 +++++++++++ tapset/linux/i386/nd_syscalls.stp | 4 +- tapset/linux/i386/syscalls.stp | 5 +- tapset/linux/x86_64/aux_syscalls.stp | 30 +++++++++++ tapset/linux/x86_64/nd_syscalls.stp | 38 ++++++++++++++ tapset/linux/x86_64/syscalls.stp | 34 +++++++++++++ .../buildok/nd_syscalls-arch-detailed.stp | 21 ++++++++ testsuite/buildok/syscalls-arch-detailed.stp | 20 ++++++++ testsuite/systemtap.syscall/thread_area.c | 51 +++++++++++++++++++ 9 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 testsuite/systemtap.syscall/thread_area.c diff --git a/tapset/linux/i386/aux_syscalls.stp b/tapset/linux/i386/aux_syscalls.stp index b7ba8bd48..0c158e5d4 100644 --- a/tapset/linux/i386/aux_syscalls.stp +++ b/tapset/linux/i386/aux_syscalls.stp @@ -68,3 +68,33 @@ function _ptrace_return_arch_prctl_addr:long(request:long, addr:long, data:long) { return 0 } + +%{ +#include +%} + +function _struct_user_desc_u:string(uaddr:long) +%{ /* pure */ + struct user_desc ud; + char *ptr = (char *)(unsigned long)STAP_ARG_uaddr; + if (ptr == NULL) + strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN); + else + { + if (_stp_copy_from_user((char*)&ud, ptr, + sizeof(struct user_desc)) == 0) + { + snprintf(STAP_RETVALUE, MAXSTRINGLEN, + "{entry_number=%u, base_addr=%lu, limit=%u, seg_32bit=%u, contents=%u, " + "read_exec_only=%u, limit_in_pages=%u, seg_not_present=%u, useable=%u}", + ud.entry_number, (unsigned long)ud.base_addr, ud.limit, ud.seg_32bit, ud.contents, + ud.read_exec_only, ud.limit_in_pages, ud.seg_not_present, ud.useable); + } + else + { + snprintf(STAP_RETVALUE, MAXSTRINGLEN, "0x%lx", + (unsigned long)ptr); + } + } +%} + diff --git a/tapset/linux/i386/nd_syscalls.stp b/tapset/linux/i386/nd_syscalls.stp index aa139a013..4971209bf 100644 --- a/tapset/linux/i386/nd_syscalls.stp +++ b/tapset/linux/i386/nd_syscalls.stp @@ -13,7 +13,7 @@ probe nd_syscall.get_thread_area = kprobe.function("sys_get_thread_area") // u_info_uaddr = $u_info asmlinkage() u_info_uaddr = pointer_arg(1) - argstr = sprintf("%p", u_info_uaddr) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) } probe nd_syscall.get_thread_area.return = kprobe.function("sys_get_thread_area").return { @@ -132,7 +132,7 @@ probe nd_syscall.set_thread_area = kprobe.function("sys_set_thread_area") // u_info_uaddr = $u_info asmlinkage() u_info_uaddr = pointer_arg(1) - argstr = sprintf("%p", u_info_uaddr) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) } probe nd_syscall.set_thread_area.return = kprobe.function("sys_set_thread_area").return { diff --git a/tapset/linux/i386/syscalls.stp b/tapset/linux/i386/syscalls.stp index fba335f71..28fdc8392 100644 --- a/tapset/linux/i386/syscalls.stp +++ b/tapset/linux/i386/syscalls.stp @@ -11,7 +11,7 @@ probe syscall.get_thread_area = kernel.function("sys_get_thread_area") { name = "get_thread_area" u_info_uaddr = $u_info - argstr = sprintf("%p", u_info_uaddr) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) } probe syscall.get_thread_area.return = kernel.function("sys_get_thread_area").return { @@ -115,13 +115,14 @@ probe syscall.set_thread_area = kernel.function("sys_set_thread_area") { name = "set_thread_area" u_info_uaddr = $u_info - argstr = sprintf("%p", u_info_uaddr) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) } probe syscall.set_thread_area.return = kernel.function("sys_set_thread_area").return { name = "set_thread_area" retstr = return_str(1, $return) } + # set_zone_reclaim ___________________________________________ /* * asmlinkage long diff --git a/tapset/linux/x86_64/aux_syscalls.stp b/tapset/linux/x86_64/aux_syscalls.stp index 9765a1c5a..80479d979 100644 --- a/tapset/linux/x86_64/aux_syscalls.stp +++ b/tapset/linux/x86_64/aux_syscalls.stp @@ -92,3 +92,33 @@ function _ptrace_return_arch_prctl_addr(request, addr, data) || data == %{ /* pure */ ARCH_GET_GS %})) return user_long(addr) } + +%{ +#include +%} + +function _struct_user_desc_u:string(uaddr:long) +%{ /* pure */ + struct user_desc ud; + char *ptr = (char *)(unsigned long)STAP_ARG_uaddr; + if (ptr == NULL) + strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN); + else + { + if (_stp_copy_from_user((char*)&ud, ptr, + sizeof(struct user_desc)) == 0) + { + snprintf(STAP_RETVALUE, MAXSTRINGLEN, + "{entry_number=%u, base_addr=%u, limit=%u, seg_32bit=%u, contents=%u, " + "read_exec_only=%u, limit_in_pages=%u, seg_not_present=%u, useable=%u, lm=%u}", + ud.entry_number, ud.base_addr, ud.limit, ud.seg_32bit, ud.contents, + ud.read_exec_only, ud.limit_in_pages, ud.seg_not_present, ud.useable, ud.lm); + } + else + { + snprintf(STAP_RETVALUE, MAXSTRINGLEN, "0x%lx", + (unsigned long)ptr); + } + } +%} + diff --git a/tapset/linux/x86_64/nd_syscalls.stp b/tapset/linux/x86_64/nd_syscalls.stp index 6a8d6844f..4b667d9e8 100644 --- a/tapset/linux/x86_64/nd_syscalls.stp +++ b/tapset/linux/x86_64/nd_syscalls.stp @@ -23,6 +23,25 @@ probe nd_syscall.arch_prctl.return = kprobe.function("sys_arch_prctl").return retstr = returnstr(1) } +# get_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_get_thread_area(struct user_desc __user *u_info) + */ +probe nd_syscall.get_thread_area = kprobe.function("sys_get_thread_area") +{ + name = "get_thread_area" + // u_info_uaddr = $u_info + asmlinkage() + u_info_uaddr = pointer_arg(1) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) +} +probe nd_syscall.get_thread_area.return = kprobe.function("sys_get_thread_area").return +{ + name = "get_thread_area" + retstr = returnstr(1) +} + # iopl _______________________________________________________ # long sys_iopl(unsigned int level, struct pt_regs *regs); # NOTE. This function is only in i386 and x86_64 and its args vary @@ -42,6 +61,25 @@ probe nd_syscall.iopl.return = kprobe.function("sys_iopl").return retstr = returnstr(1) } +# set_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_set_thread_area(struct user_desc __user *u_info) + */ +probe nd_syscall.set_thread_area = kprobe.function("sys_set_thread_area") +{ + name = "set_thread_area" + // u_info_uaddr = $u_info + asmlinkage() + u_info_uaddr = pointer_arg(1) + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) +} +probe nd_syscall.set_thread_area.return = kprobe.function("sys_set_thread_area").return +{ + name = "set_thread_area" + retstr = returnstr(1) +} + %( CONFIG_GENERIC_SIGALTSTACK == "n" || kernel_v < "3.8" %? # sigaltstack ________________________________________________ # long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, diff --git a/tapset/linux/x86_64/syscalls.stp b/tapset/linux/x86_64/syscalls.stp index 2bfdd5cc4..fe4dd2bb7 100644 --- a/tapset/linux/x86_64/syscalls.stp +++ b/tapset/linux/x86_64/syscalls.stp @@ -19,6 +19,23 @@ probe syscall.arch_prctl.return = kernel.function("sys_arch_prctl").return retstr = return_str(1, $return) } +# get_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_get_thread_area(struct user_desc __user *u_info) + */ +probe syscall.get_thread_area = kernel.function("sys_get_thread_area") +{ + name = "get_thread_area" + u_info_uaddr = $u_info + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) +} +probe syscall.get_thread_area.return = kernel.function("sys_get_thread_area").return +{ + name = "get_thread_area" + retstr = return_str(1, $return) +} + # iopl _______________________________________________________ # long sys_iopl(unsigned int level, struct pt_regs *regs); # NOTE. This function is only in i386 and x86_64 and its args vary @@ -36,6 +53,23 @@ probe syscall.iopl.return = kernel.function("sys_iopl").return retstr = return_str(1, $return) } +# set_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_set_thread_area(struct user_desc __user *u_info) + */ +probe syscall.set_thread_area = kernel.function("sys_set_thread_area") +{ + name = "set_thread_area" + u_info_uaddr = $u_info + argstr = sprintf("%s", _struct_user_desc_u(u_info_uaddr)) +} +probe syscall.set_thread_area.return = kernel.function("sys_set_thread_area").return +{ + name = "set_thread_area" + retstr = return_str(1, $return) +} + %( CONFIG_GENERIC_SIGALTSTACK == "n" || kernel_v < "3.8" %? # sigaltstack ________________________________________________ # long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, diff --git a/testsuite/buildok/nd_syscalls-arch-detailed.stp b/testsuite/buildok/nd_syscalls-arch-detailed.stp index 6b468f504..ab4afe4c4 100755 --- a/testsuite/buildok/nd_syscalls-arch-detailed.stp +++ b/testsuite/buildok/nd_syscalls-arch-detailed.stp @@ -562,3 +562,24 @@ probe nd_syscall.compat_readahead.return ? { printf("%s, %s\n", name, retstr) } + +probe nd_syscall.get_thread_area ? +{ + printf("%s, %s\n", name, argstr) + printf("%p\n", u_info_uaddr) +} +probe nd_syscall.get_thread_area.return ? +{ + printf("%s, %s\n", name, retstr) +} + +probe nd_syscall.set_thread_area ? +{ + printf("%s, %s\n", name, argstr) + printf("%p\n", u_info_uaddr) +} +probe nd_syscall.set_thread_area.return ? +{ + printf("%s, %s\n", name, retstr) +} + diff --git a/testsuite/buildok/syscalls-arch-detailed.stp b/testsuite/buildok/syscalls-arch-detailed.stp index 4b000eabb..c170c14f6 100755 --- a/testsuite/buildok/syscalls-arch-detailed.stp +++ b/testsuite/buildok/syscalls-arch-detailed.stp @@ -562,3 +562,23 @@ probe syscall.compat_readahead.return ? { printf("%s, %s\n", name, retstr) } + +probe syscall.get_thread_area ? +{ + printf("%s, %s\n", name, argstr) + printf("%p\n", u_info_uaddr) +} +probe syscall.get_thread_area.return ? +{ + printf("%s, %s\n", name, retstr) +} + +probe syscall.set_thread_area ? +{ + printf("%s, %s\n", name, argstr) + printf("%p\n", u_info_uaddr) +} +probe syscall.set_thread_area.return ? +{ + printf("%s, %s\n", name, retstr) +} diff --git a/testsuite/systemtap.syscall/thread_area.c b/testsuite/systemtap.syscall/thread_area.c new file mode 100644 index 000000000..d36ad00ad --- /dev/null +++ b/testsuite/systemtap.syscall/thread_area.c @@ -0,0 +1,51 @@ +/* COVERAGE: get_thread_area set_thread_area */ + +#define _GNU_SOURCE +#include +#include +#include + +#if defined __NR_get_thread_area && defined __NR_set_thread_area + +#include + +static inline int +__get_thread_area(struct user_desc *u_info) +{ + return syscall(__NR_get_thread_area, u_info); +} + +static inline int +__set_thread_area(struct user_desc *u_info) +{ + return syscall(__NR_set_thread_area, u_info); +} + +int +main() +{ + struct user_desc ud; + ud.entry_number = -1; + __set_thread_area(&ud); + //staptest// [[[[set_thread_area ({entry_number=XXXX, base_addr=XXXX, limit=XXXX, seg_32bit=XXXX, contents=XXXX, read_exec_only=XXXX, limit_in_pages=XXXX, seg_not_present=XXXX, useable=XXXX[[[[, lm=XXXX!!!!]]]]})!!!!ni_syscall ()]]]] = NNNN + + __get_thread_area(&ud); + //staptest// [[[[get_thread_area ({entry_number=XXXX, base_addr=XXXX, limit=XXXX, seg_32bit=XXXX, contents=XXXX, read_exec_only=XXXX, limit_in_pages=XXXX, seg_not_present=XXXX, useable=XXXX[[[[, lm=XXXX!!!!]]]]})!!!!ni_syscall ()]]]] = NNNN + + // Limit testing + + __set_thread_area((struct user_desc *)-1); + //staptest// [[[[set_thread_area (0x[f]+)!!!!ni_syscall ()]]]] = NNNN + + __get_thread_area((struct user_desc *)-1); + //staptest// [[[[get_thread_area (0x[f]+)!!!!ni_syscall ()]]]] = NNNN + + return 0; +} +#else +int +main() +{ + return 0; +} +#endif -- 2.43.5