diff --git a/configure.in b/configure.in index d0a4ee7cb..d22871e4e 100644 --- a/configure.in +++ b/configure.in @@ -1683,6 +1683,8 @@ AC_CHECK_FUNCS([ \ strstr \ syscall \ utimensat \ + process_vm_readv \ + process_vm_writev \ ]) # AC_CHECK_LIB adds any library found to the variable LIBS, and links these diff --git a/coregrind/m_syswrap/priv_syswrap-linux.h b/coregrind/m_syswrap/priv_syswrap-linux.h index 1d0f5b79d..8c073a1f7 100644 --- a/coregrind/m_syswrap/priv_syswrap-linux.h +++ b/coregrind/m_syswrap/priv_syswrap-linux.h @@ -263,6 +263,10 @@ DECL_TEMPLATE(linux, sys_delete_module); // Linux-specific (oprofile-related) DECL_TEMPLATE(linux, sys_lookup_dcookie); // (*/32/64) L +// Linux-specific (new in Linux 3.2) +DECL_TEMPLATE(linux, sys_process_vm_readv); +DECL_TEMPLATE(linux, sys_process_vm_writev); + /* --------------------------------------------------------------------- Wrappers for sockets and ipc-ery. These are split into standalone procedures because x86-linux hides them inside multiplexors diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c index 3b69919a1..282ae40cc 100644 --- a/coregrind/m_syswrap/syswrap-amd64-linux.c +++ b/coregrind/m_syswrap/syswrap-amd64-linux.c @@ -1423,7 +1423,10 @@ static SyscallTableEntry syscall_table[] = { // LINX_(__NR_syncfs, sys_ni_syscall), // 306 // LINX_(__NR_sendmmsg, sys_ni_syscall), // 307 // LINX_(__NR_setns, sys_ni_syscall), // 308 - LINXY(__NR_getcpu, sys_getcpu) // 309 + LINXY(__NR_getcpu, sys_getcpu), // 309 + + LINXY(__NR_process_vm_readv, sys_process_vm_readv), // 310 + LINX_(__NR_process_vm_writev, sys_process_vm_writev) // 311 }; SyscallTableEntry* ML_(get_linux_syscall_entry) ( UInt sysno ) diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 5a62f5927..edf7d38a2 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -3471,6 +3471,73 @@ PRE(sys_pwritev) } } +/* --------------------------------------------------------------------- + process_vm_{read,write}v wrappers + ------------------------------------------------------------------ */ + +PRE(sys_process_vm_readv) +{ + PRINT("sys_process_vm_readv ( %lu, %#lx, %lu, %#lx, %lu, %lu )", + ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "process_vm_readv", + vki_pid_t, pid, + const struct iovec *, lvec, + unsigned long, liovcnt, + const struct iovec *, rvec, + unsigned long, riovcnt, + unsigned long, flags); + PRE_MEM_READ( "process_vm_readv(lvec)", + ARG2, ARG3 * sizeof(struct vki_iovec) ); + PRE_MEM_READ( "process_vm_readv(rvec)", + ARG4, ARG5 * sizeof(struct vki_iovec) ); + if (ARG2 != 0) { + /* TODO: Don't do any of the following if lvec is invalid */ + const struct vki_iovec *vec = (const struct vki_iovec *)ARG2; + UInt i; + for (i = 0; i < ARG3; i++) + PRE_MEM_WRITE( "process_vm_readv(lvec[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } +} + +POST(sys_process_vm_readv) +{ + const struct vki_iovec *vec = (const struct vki_iovec *)ARG2; + UInt remains = RES; + UInt i; + for (i = 0; i < ARG3; i++) { + UInt nReadThisBuf = vec[i].iov_len <= remains ? + vec[i].iov_len : remains; + POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf ); + remains -= nReadThisBuf; + } +} + +PRE(sys_process_vm_writev) +{ + PRINT("sys_process_vm_writev ( %lu, %#lx, %lu, %#lx, %lu, %lu )", + ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "process_vm_writev", + vki_pid_t, pid, + const struct iovec *, lvec, + unsigned long, liovcnt, + const struct iovec *, rvec, + unsigned long, riovcnt, + unsigned long, flags); + PRE_MEM_READ( "process_vm_writev(lvec)", + ARG2, ARG3 * sizeof(struct vki_iovec) ); + PRE_MEM_READ( "process_vm_writev(rvec)", + ARG4, ARG5 * sizeof(struct vki_iovec) ); + if (ARG2 != 0) { + /* TODO: Don't do any of the following if lvec is invalid */ + const struct vki_iovec *vec = (const struct vki_iovec *)ARG2; + UInt i; + for (i = 0; i < ARG3; i++) + PRE_MEM_READ( "process_vm_writev(lvec[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } +} + /* --------------------------------------------------------------------- key retention service wrappers ------------------------------------------------------------------ */ diff --git a/coregrind/m_syswrap/syswrap-ppc32-linux.c b/coregrind/m_syswrap/syswrap-ppc32-linux.c index 6a62867ec..005283da3 100644 --- a/coregrind/m_syswrap/syswrap-ppc32-linux.c +++ b/coregrind/m_syswrap/syswrap-ppc32-linux.c @@ -1827,7 +1827,10 @@ static SyscallTableEntry syscall_table[] = { LINXY(__NR_perf_event_open, sys_perf_event_open), // 319 LINXY(__NR_preadv, sys_preadv), // 320 LINX_(__NR_pwritev, sys_pwritev), // 321 - LINXY(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) // 322 + LINXY(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo),// 322 + + LINXY(__NR_process_vm_readv, sys_process_vm_readv), // 351 + LINX_(__NR_process_vm_writev, sys_process_vm_writev) // 352 }; SyscallTableEntry* ML_(get_linux_syscall_entry) ( UInt sysno ) diff --git a/coregrind/m_syswrap/syswrap-ppc64-linux.c b/coregrind/m_syswrap/syswrap-ppc64-linux.c index fbb5ba517..5f778abfd 100644 --- a/coregrind/m_syswrap/syswrap-ppc64-linux.c +++ b/coregrind/m_syswrap/syswrap-ppc64-linux.c @@ -1467,7 +1467,10 @@ static SyscallTableEntry syscall_table[] = { LINXY(__NR_perf_event_open, sys_perf_event_open), // 319 LINXY(__NR_preadv, sys_preadv), // 320 LINX_(__NR_pwritev, sys_pwritev), // 321 - LINXY(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) // 322 + LINXY(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo),// 322 + + LINXY(__NR_process_vm_readv, sys_process_vm_readv), // 351 + LINX_(__NR_process_vm_writev, sys_process_vm_writev) // 352 }; SyscallTableEntry* ML_(get_linux_syscall_entry) ( UInt sysno ) diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c index b0b821f95..8120e4081 100644 --- a/coregrind/m_syswrap/syswrap-x86-linux.c +++ b/coregrind/m_syswrap/syswrap-x86-linux.c @@ -2223,7 +2223,7 @@ static SyscallTableEntry syscall_table[] = { // LINX_(__NR_fanotify_init, sys_ni_syscall), // 338 // LINX_(__NR_fanotify_mark, sys_ni_syscall), // 339 - LINXY(__NR_prlimit64, sys_prlimit64) // 340 + LINXY(__NR_prlimit64, sys_prlimit64), // 340 // LINX_(__NR_name_to_handle_at, sys_ni_syscall), // 341 // LINX_(__NR_open_by_handle_at, sys_ni_syscall), // 342 // LINX_(__NR_clock_adjtime, sys_ni_syscall), // 343 @@ -2231,6 +2231,8 @@ static SyscallTableEntry syscall_table[] = { // LINX_(__NR_sendmmsg, sys_ni_syscall), // 345 // LINX_(__NR_setns, sys_ni_syscall), // 346 + LINXY(__NR_process_vm_readv, sys_process_vm_readv), // 347 + LINX_(__NR_process_vm_writev, sys_process_vm_writev) // 348 }; SyscallTableEntry* ML_(get_linux_syscall_entry) ( UInt sysno ) diff --git a/memcheck/tests/x86-linux/scalar.c b/memcheck/tests/x86-linux/scalar.c index d4a89e538..55c64faeb 100644 --- a/memcheck/tests/x86-linux/scalar.c +++ b/memcheck/tests/x86-linux/scalar.c @@ -1257,6 +1257,14 @@ int main(void) GO(__NR_epoll_create1, "1s 0m"); SY(__NR_epoll_create1, x0); SUCC_OR_FAIL; + // __NR_process_vm_readv 347 + GO(__NR_process_vm_readv, "6s 2m"); + SY(__NR_process_vm_readv, x0, x0, x0+1, x0, x0+1, x0); FAIL; + + // __NR_process_vm_writev 348 + GO(__NR_process_vm_writev, "6s 2m"); + SY(__NR_process_vm_writev, x0, x0, x0+1, x0, x0+1, x0); FAIL; + // no such syscall... GO(9999, "1e"); SY(9999); FAIL; diff --git a/memcheck/tests/x86-linux/scalar.stderr.exp b/memcheck/tests/x86-linux/scalar.stderr.exp index 894bcb9d3..364e6e7f6 100644 --- a/memcheck/tests/x86-linux/scalar.stderr.exp +++ b/memcheck/tests/x86-linux/scalar.stderr.exp @@ -3977,6 +3977,80 @@ Syscall param epoll_create1(flags) contains uninitialised byte(s) ... by 0x........: main (scalar.c:1258) +----------------------------------------------------- +347:__NR_process_vm_readv 6s 2m +----------------------------------------------------- +Syscall param process_vm_readv(pid) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(lvec) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(liovcnt) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(rvec) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(riovcnt) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(flags) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1262) + +Syscall param process_vm_readv(lvec) points to unaddressable byte(s) + ... + by 0x........: main (scalar.c:1262) + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +Syscall param process_vm_readv(rvec) points to unaddressable byte(s) + ... + by 0x........: main (scalar.c:1262) + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +----------------------------------------------------- +348:__NR_process_vm_writev 6s 2m +----------------------------------------------------- +Syscall param process_vm_writev(pid) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(lvec) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(liovcnt) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(rvec) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(riovcnt) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(flags) contains uninitialised byte(s) + ... + by 0x........: main (scalar.c:1266) + +Syscall param process_vm_writev(lvec) points to unaddressable byte(s) + ... + by 0x........: main (scalar.c:1266) + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +Syscall param process_vm_writev(rvec) points to unaddressable byte(s) + ... + by 0x........: main (scalar.c:1266) + Address 0x........ is not stack'd, malloc'd or (recently) free'd + ----------------------------------------------------- 9999: 9999 1e ----------------------------------------------------- @@ -3990,5 +4064,5 @@ it at http://valgrind.org/support/bug_reports.html. ----------------------------------------------------- Syscall param exit(status) contains uninitialised byte(s) ... - by 0x........: main (scalar.c:1266) + by 0x........: main (scalar.c:1274) diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am index 49350c763..d0804f29a 100644 --- a/none/tests/Makefile.am +++ b/none/tests/Makefile.am @@ -160,7 +160,8 @@ EXTRA_DIST = \ threadederrno.vgtest \ timestamp.stderr.exp timestamp.vgtest \ tls.vgtest tls.stderr.exp tls.stdout.exp \ - vgprintf.stderr.exp vgprintf.vgtest + vgprintf.stderr.exp vgprintf.vgtest \ + process_vm_readv_writev.stderr.exp process_vm_readv_writev.vgtest check_PROGRAMS = \ ansi args \ @@ -198,7 +199,8 @@ check_PROGRAMS = \ valgrind_cpp_test \ vgprintf \ coolo_sigaction \ - gxx304 + gxx304 \ + process_vm_readv_writev # DDD: # - manythreads and thread-exits have lots of this: diff --git a/none/tests/process_vm_readv_writev.c b/none/tests/process_vm_readv_writev.c new file mode 100644 index 000000000..851cd335a --- /dev/null +++ b/none/tests/process_vm_readv_writev.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include + +static int status = EXIT_SUCCESS; + +#ifdef HAVE_PROCESS_VM_READV + +static void test_process_vm_readv() +{ + char lbuf[] = "123456"; + char rbuf[] = "ABCDEF"; + + struct iovec lvec[2]; + struct iovec rvec[2]; + + lvec[0].iov_base = lbuf + 1; + lvec[0].iov_len = 1; + lvec[1].iov_base = lbuf + 3; + lvec[1].iov_len = 2; + + rvec[0].iov_base = rbuf + 1; + rvec[0].iov_len = 2; + rvec[1].iov_base = rbuf + 4; + rvec[1].iov_len = 1; + + if (process_vm_readv(getpid(), + lvec, 2, + rvec, 2, + 0 ) < 0 ) { + perror("process_vm_readv"); + status = EXIT_FAILURE; + } + + if (strcmp(lbuf, "1B3CE6") != 0) { + fprintf(stderr, "Expected: \"1B3CE6\"; Got: \"%s\"\n", lbuf); + status = EXIT_FAILURE; + } +} + +#endif /* defined( HAVE_PROCESS_VM_READV ) */ + +#ifdef HAVE_PROCESS_VM_WRITEV + +static void test_process_vm_writev() +{ + char lbuf[] = "123456"; + char rbuf[] = "ABCDEF"; + + struct iovec lvec[2]; + struct iovec rvec[2]; + + lvec[0].iov_base = lbuf + 1; + lvec[0].iov_len = 1; + lvec[1].iov_base = lbuf + 3; + lvec[1].iov_len = 2; + + rvec[0].iov_base = rbuf + 1; + rvec[0].iov_len = 2; + rvec[1].iov_base = rbuf + 4; + rvec[1].iov_len = 1; + + if (process_vm_writev(getpid(), + lvec, 2, + rvec, 2, + 0 ) < 0 ) { + perror("process_vm_writev"); + status = EXIT_FAILURE; + } + + if (strcmp(rbuf, "A24D5F") != 0) { + fprintf(stderr, "Expected: \"A24D5F\"; Got: \"%s\"\n", rbuf); + status = EXIT_FAILURE; + } +} + +#endif /* defined( HAVE_PROCESS_VM_WRITEV ) */ + +int main(int argc, char *argv[]) +{ +#ifdef HAVE_PROCESS_VM_READV + test_process_vm_readv(); +#endif +#ifdef HAVE_PROCESS_VM_WRITEV + test_process_vm_writev(); +#endif + return status; +} diff --git a/none/tests/process_vm_readv_writev.stderr.exp b/none/tests/process_vm_readv_writev.stderr.exp new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/none/tests/process_vm_readv_writev.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/process_vm_readv_writev.vgtest b/none/tests/process_vm_readv_writev.vgtest new file mode 100644 index 000000000..4094ab030 --- /dev/null +++ b/none/tests/process_vm_readv_writev.vgtest @@ -0,0 +1 @@ +prog: process_vm_readv_writev