Various amd64 syscall improvements (Tom Hughes)


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3425 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/amd64-linux/syscalls.c b/coregrind/amd64-linux/syscalls.c
index 6874670..35197b3 100644
--- a/coregrind/amd64-linux/syscalls.c
+++ b/coregrind/amd64-linux/syscalls.c
@@ -539,30 +539,37 @@
 
 PRE(sys_setsockopt, 0)
 {
-   /* int setsockopt(int s, int level, int optname, 
-                     const void *optval, int optlen); */
+   PRINT("sys_setsockopt ( %d, %d, %d, %p, %d ",ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "setsockopt",
+                 int, s, int, level, int, optname,
+                 const void *, optval, int, optlen);
    VG_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
 }
 
 PRE(sys_connect, MayBlock)
 {
-   /* int connect(int sockfd, 
-                  struct sockaddr *serv_addr, int addrlen ); */
+   PRINT("sys_connect ( %d, %p, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "connect",
+                 int, sockfd, struct sockaddr *, serv_addr, int, addrlen);
    VG_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
 }
 
 PRE(sys_sendto, MayBlock)
 {
-   /* int sendto(int s, const void *msg, int len, 
-                 unsigned int flags, 
-                 const struct sockaddr *to, int tolen); */
+   PRINT("sys_sendto ( %d, %s, %d, %u, %p, %d )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(int, "sendto",
+                 int, s, const void *, msg, int, len, 
+                 unsigned int, flags, 
+                 const struct sockaddr *, to, int, tolen);
    VG_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
 }
 
 PRE(sys_recvfrom, MayBlock)
 {
-   /* int recvfrom(int s, void *buf, int len, unsigned int flags,
-                   struct sockaddr *from, int *fromlen); */
+   PRINT("sys_recvfrom ( %d, %p, %d, %u, %p, %p )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(int, "recvfrom",
+                 int, s, void *, buf, int, len, unsigned int, flags,
+                 struct sockaddr *, from, int *, fromlen);
    VG_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
 }
 POST(sys_recvfrom)
@@ -572,13 +579,16 @@
 
 PRE(sys_sendmsg, MayBlock)
 {
-   /* int sendmsg(int s, const struct msghdr *msg, int flags); */
+   PRINT("sys_sendmsg ( %d, %p, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "sendmsg",
+                 int, s, const struct msghdr *, msg, int, flags);
    VG_(generic_PRE_sys_sendmsg)(tid, ARG1,ARG2);
 }
 
 PRE(sys_recvmsg, MayBlock)
 {
-   /* int recvmsg(int s, struct msghdr *msg, int flags); */
+   PRINT("sys_recvmsg ( %d, %p, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "recvmsg", int, s, struct msghdr *, msg, int, flags);
    VG_(generic_PRE_sys_recvmsg)(tid, ARG1,ARG2);
 }
 POST(sys_recvmsg)
@@ -588,11 +598,15 @@
 
 PRE(sys_shutdown, MayBlock)
 {
-   /* int shutdown(int s, int how); */
+   PRINT("sys_shutdown ( %d, %d )",ARG1,ARG2);
+   PRE_REG_READ2(int, "shutdown", int, s, int, how);
 }
 
 PRE(sys_getsockname, MayBlock)
 {
+   PRINT("sys_getsockname ( %d, %p, %p )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "getsockname",
+                 int, s, struct sockaddr *, name, int *, namelen);
    VG_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3);
 }
 POST(sys_getsockname)
@@ -602,6 +616,9 @@
 
 PRE(sys_getpeername, MayBlock)
 {
+   PRINT("sys_getpeername ( %d, %p, %p )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "getpeername",
+                 int, s, struct sockaddr *, name, int *, namelen);
    VG_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3);
 }
 POST(sys_getpeername)
@@ -609,6 +626,171 @@
    VG_(generic_POST_sys_getpeername)(tid, RES,ARG1,ARG2,ARG3);
 }
 
+PRE(sys_socketpair, MayBlock)
+{
+   PRINT("sys_socketpair ( %d, %d, %d, %p )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "socketpair",
+                 int, d, int, type, int, protocol, int [2], sv);
+   VG_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+POST(sys_socketpair)
+{
+   VG_(generic_POST_sys_socketpair)(tid, RES,ARG1,ARG2,ARG3,ARG4);
+}
+
+PRE(sys_semget, 0)
+{
+   PRINT("sys_semget ( %d, %d, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "semget", key_t, key, int, nsems, int, semflg);
+}
+
+PRE(sys_semop, MayBlock)
+{
+   PRINT("sys_semop ( %d, %p, %u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "semop",
+                 int, semid, struct sembuf *, sops, unsigned, nsoops);
+   VG_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
+}
+
+PRE(sys_semtimedop, MayBlock)
+{
+   PRINT("sys_semtimedop ( %d, %p, %u, %p )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "semtimedop",
+                 int, semid, struct sembuf *, sops, unsigned, nsoops,
+                 struct timespec *, timeout);
+   VG_(generic_PRE_sys_semtimedop)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+
+PRE(sys_semctl, 0)
+{
+   switch (ARG3 & ~VKI_IPC_64) {
+   case VKI_IPC_INFO:
+   case VKI_SEM_INFO:
+      PRINT("sys_semctl ( %d, %d, %d, %p )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "semctl",
+                    int, semid, int, semnum, int, cmd, struct seminfo *, arg);
+      break;
+   case VKI_IPC_STAT:
+   case VKI_SEM_STAT:
+   case VKI_IPC_SET:
+      PRINT("sys_semctl ( %d, %d, %d, %p )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "semctl",
+                    int, semid, int, semnum, int, cmd, struct semid_ds *, arg);
+      break;
+   case VKI_GETALL:
+   case VKI_SETALL:
+      PRINT("sys_semctl ( %d, %d, %d, %p )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "semctl",
+                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
+      break;
+   default:
+      PRINT("sys_semctl ( %d, %d, %d )",ARG1,ARG2,ARG3);
+      PRE_REG_READ3(int, "semctl",
+                    int, semid, int, semnum, int, cmd);
+      break;
+   }
+   VG_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+
+POST(sys_semctl)
+{
+   VG_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
+}
+
+PRE(sys_msgget, 0)
+{
+   PRINT("sys_msgget ( %d, %d )",ARG1,ARG2);
+   PRE_REG_READ2(int, "msgget", key_t, key, int, msgflg);
+}
+
+PRE(sys_msgsnd, 0)
+{
+   PRINT("sys_msgsnd ( %d, %p, %d, %d )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "msgsnd",
+                 int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg);
+   VG_(generic_PRE_sys_msgsnd)(tid, ARG1,ARG2,ARG3,ARG4);
+      /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
+            tst->sys_flags |= MayBlock;
+      */
+}
+
+PRE(sys_msgrcv, 0)
+{
+   PRINT("sys_msgrcv ( %d, %p, %d, %d, %d )",ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "msgrcv",
+                 int, msqid, struct msgbuf *, msgp, size_t, msgsz,
+                 long, msgytp, int, msgflg);
+   VG_(generic_PRE_sys_msgrcv)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
+      /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
+            tst->sys_flags |= MayBlock;
+      */
+}
+
+POST(sys_msgrcv)
+{
+   VG_(generic_POST_sys_msgrcv)(tid, RES,ARG1,ARG2,ARG3,ARG4,ARG5);
+}
+
+PRE(sys_msgctl, 0)
+{
+   PRINT("sys_msgctl ( %d, %d, %p )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "msgctl",
+                 int, msqid, int, cmd, struct msqid_ds *, buf);
+   VG_(generic_PRE_sys_msgctl)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_msgctl)
+{
+   VG_(generic_POST_sys_msgctl)(tid, RES,ARG1,ARG2,ARG3);
+}
+
+PRE(sys_shmget, 0)
+{
+   PRINT("sys_shmget ( %d, %d, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "shmget", key_t, key, size_t, size, int, shmflg);
+}
+
+PRE(wrap_sys_shmat, 0)
+{
+   PRINT("wrap_sys_shmat ( %d, %p, %d )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(void *, "shmat",
+                 int, shmid, const void *, shmaddr, int, shmflg);
+   ARG2 = VG_(generic_PRE_sys_shmat)(tid, ARG1,ARG2,ARG3);
+   if (ARG2 == 0)
+      SET_RESULT( -VKI_EINVAL );
+}
+
+POST(wrap_sys_shmat)
+{
+   VG_(generic_POST_sys_shmat)(tid, RES,ARG1,ARG2,ARG3);
+}
+
+PRE(sys_shmdt, 0)
+{
+   PRINT("sys_shmdt ( %p )",ARG1);
+   PRE_REG_READ1(int, "shmdt", const void *, shmaddr);
+   if (!VG_(generic_PRE_sys_shmdt)(tid, ARG1))
+      SET_RESULT( -VKI_EINVAL );
+}
+
+POST(sys_shmdt)
+{
+   VG_(generic_POST_sys_shmdt)(tid, RES,ARG1);
+}
+
+PRE(sys_shmctl, 0)
+{
+   PRINT("sys_shmctl ( %d, %d, %p )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "shmctl",
+                 int, shmid, int, cmd, struct shmid_ds *, buf);
+   VG_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_shmctl)
+{
+   VG_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2,ARG3);
+}
+
 #undef PRE
 #undef POST
 
@@ -664,12 +846,12 @@
    //   (__NR_msync,             sys_msync),          // 26 
    //   (__NR_mincore,           sys_mincore),        // 27 
    GENX_(__NR_madvise,           sys_madvise),        // 28 
-   //   (__NR_shmget,            sys_shmget),         // 29 
+   PLAX_(__NR_shmget,            sys_shmget),         // 29 
 
-   //   (__NR_shmat,             wrap_sys_shmat),     // 30 
-   //   (__NR_shmctl,            sys_shmctl),         // 31 
-   //   (__NR_dup,               sys_dup),            // 32 
-   //   (__NR_dup2,              sys_dup2),           // 33 
+   PLAXY(__NR_shmat,             wrap_sys_shmat),     // 30 
+   PLAXY(__NR_shmctl,            sys_shmctl),         // 31 
+   GENXY(__NR_dup,               sys_dup),            // 32 
+   GENXY(__NR_dup2,              sys_dup2),           // 33 
    //   (__NR_pause,             sys_pause),          // 34 
 
    //   (__NR_nanosleep,         sys_nanosleep),      // 35 
@@ -693,36 +875,36 @@
    //   (__NR_listen,            sys_listen),         // 50 
    PLAXY(__NR_getsockname,       sys_getsockname),    // 51 
    PLAXY(__NR_getpeername,       sys_getpeername),    // 52 
-   //   (__NR_socketpair,        sys_socketpair),     // 53 
+   PLAXY(__NR_socketpair,        sys_socketpair),     // 53 
    PLAX_(__NR_setsockopt,        sys_setsockopt),     // 54
 
    //   (__NR_getsockopt,        sys_getsockopt),     // 55 
    //   (__NR_clone,             stub_clone),         // 56 
    //   (__NR_fork,              stub_fork),          // 57 
    //   (__NR_vfork,             stub_vfork),         // 58 
-   //   (__NR_execve,            stub_execve),        // 59 
+   GENX_(__NR_execve,            sys_execve),         // 59 
 
    GENX_(__NR_exit,              sys_exit),           // 60
-   //   (__NR_wait4,             sys_wait4),          // 61 
+   GENXY(__NR_wait4,             sys_wait4),          // 61 
    GENXY(__NR_kill,              sys_kill),           // 62 
    GENXY(__NR_uname,             sys_newuname),       // 63 
-   //   (__NR_semget,            sys_semget),         // 64 
+   PLAX_(__NR_semget,            sys_semget),         // 64 
 
-   //   (__NR_semop,             sys_semop),          // 65 
-   //   (__NR_semctl,            sys_semctl),         // 66 
-   //   (__NR_shmdt,             sys_shmdt),          // 67 
-   //   (__NR_msgget,            sys_msgget),         // 68 
-   //   (__NR_msgsnd,            sys_msgsnd),         // 69 
+   PLAX_(__NR_semop,             sys_semop),          // 65 
+   PLAXY(__NR_semctl,            sys_semctl),         // 66 
+   PLAXY(__NR_shmdt,             sys_shmdt),          // 67 
+   PLAX_(__NR_msgget,            sys_msgget),         // 68 
+   PLAX_(__NR_msgsnd,            sys_msgsnd),         // 69 
 
-   //   (__NR_msgrcv,            sys_msgrcv),         // 70 
-   //   (__NR_msgctl,            sys_msgctl),         // 71 
+   PLAXY(__NR_msgrcv,            sys_msgrcv),         // 70 
+   PLAXY(__NR_msgctl,            sys_msgctl),         // 71 
    GENXY(__NR_fcntl,             sys_fcntl),          // 72 
    //   (__NR_flock,             sys_flock),          // 73 
    //   (__NR_fsync,             sys_fsync),          // 74 
 
    //   (__NR_fdatasync,         sys_fdatasync),      // 75 
    //   (__NR_truncate,          sys_truncate),       // 76 
-   //   (__NR_ftruncate,         sys_ftruncate),      // 77 
+   GENX_(__NR_ftruncate,         sys_ftruncate),      // 77 
    GENXY(__NR_getdents,          sys_getdents),       // 78 
    GENXY(__NR_getcwd,            sys_getcwd),         // 79 
 
@@ -750,7 +932,7 @@
    GENXY(__NR_getrusage,         sys_getrusage),      // 98 
    //   (__NR_sysinfo,           sys_sysinfo),        // 99 
 
-   //   (__NR_times,             sys_times),          // 100 
+   GENXY(__NR_times,             sys_times),          // 100 
    //   (__NR_ptrace,            sys_ptrace),         // 101 
    GENX_(__NR_getuid,            sys_getuid),         // 102 
    //   (__NR_syslog,            sys_syslog),         // 103 
@@ -822,7 +1004,7 @@
    PLAX_(__NR_arch_prctl,	 sys_arch_prctl),     // 158 
    //   (__NR_adjtimex,          sys_adjtimex),       // 159 
 
-   //   (__NR_setrlimit,         sys_setrlimit),      // 160 
+   GENX_(__NR_setrlimit,         sys_setrlimit),      // 160 
    //   (__NR_chroot,            sys_chroot),         // 161 
    //   (__NR_sync,              sys_sync),           // 162 
    //   (__NR_acct,              sys_acct),           // 163 
@@ -894,7 +1076,7 @@
    GENX_(__NR_set_tid_address,   sys_set_tid_address),// 218 
    //   (__NR_restart_syscall,   sys_restart_syscall),// 219 
 
-   //   (__NR_semtimedop,        sys_semtimedop),     // 220 
+   PLAX_(__NR_semtimedop,        sys_semtimedop),     // 220 
    //   (__NR_fadvise64,         sys_fadvise64),      // 221 
    //   (__NR_timer_create,      sys_timer_create),   // 222 
    //   (__NR_timer_settime,     sys_timer_settime),  // 223 
@@ -919,13 +1101,13 @@
    //   (__NR_set_mempolicy,     sys_set_mempolicy),  // 238 
 
    //   (__NR_get_mempolicy,     sys_get_mempolicy),  // 239 
-   //   (__NR_mq_open,           sys_mq_open),        // 240 
-   //   (__NR_mq_unlink,         sys_mq_unlink),      // 241 
-   //   (__NR_mq_timedsend,      sys_mq_timedsend),   // 242 
-   //   (__NR_mq_timedreceive,   sys_mq_timedreceive),// 243 
+   GENXY(__NR_mq_open,           sys_mq_open),        // 240 
+   GENX_(__NR_mq_unlink,         sys_mq_unlink),      // 241 
+   GENX_(__NR_mq_timedsend,      sys_mq_timedsend),   // 242 
+   GENX_(__NR_mq_timedreceive,   sys_mq_timedreceive),// 243 
 
-   //   (__NR_mq_notify,         sys_mq_notify),      // 244 
-   //   (__NR_mq_getsetattr,     sys_mq_getsetattr),  // 245 
+   GENX_(__NR_mq_notify,         sys_mq_notify),      // 244 
+   GENXY(__NR_mq_getsetattr,     sys_mq_getsetattr),  // 245 
    //   (__NR_kexec_load,        sys_ni_syscall),     // 246 
    //   (__NR_waitid,            sys_waitid),         // 247 
 };
diff --git a/coregrind/core.h b/coregrind/core.h
index fc4cec2..25be871 100644
--- a/coregrind/core.h
+++ b/coregrind/core.h
@@ -1543,6 +1543,22 @@
 extern void  VG_(generic_PRE_sys_recvmsg)      ( TId, UW, UW );
 extern void  VG_(generic_POST_sys_recvmsg)     ( TId, UW, UW, UW );
 
+extern void  VG_(generic_PRE_sys_semop)        ( TId, UW, UW, UW );
+extern void  VG_(generic_PRE_sys_semtimedop)   ( TId, UW, UW, UW, UW );
+extern void  VG_(generic_PRE_sys_semctl)       ( TId, UW, UW, UW, UW );
+extern void  VG_(generic_POST_sys_semctl)      ( TId, UW, UW, UW, UW, UW );
+extern void  VG_(generic_PRE_sys_msgsnd)       ( TId, UW, UW, UW, UW );
+extern void  VG_(generic_PRE_sys_msgrcv)       ( TId, UW, UW, UW, UW, UW );
+extern void  VG_(generic_POST_sys_msgrcv)      ( TId, UW, UW, UW, UW, UW, UW );
+extern void  VG_(generic_PRE_sys_msgctl)       ( TId, UW, UW, UW );
+extern void  VG_(generic_POST_sys_msgctl)      ( TId, UW, UW, UW, UW );
+extern UWord VG_(generic_PRE_sys_shmat)        ( TId, UW, UW, UW );
+extern void  VG_(generic_POST_sys_shmat)       ( TId, UW, UW, UW, UW );
+extern Bool  VG_(generic_PRE_sys_shmdt)        ( TId, UW );
+extern void  VG_(generic_POST_sys_shmdt)       ( TId, UW, UW );
+extern void  VG_(generic_PRE_sys_shmctl)       ( TId, UW, UW, UW );
+extern void  VG_(generic_POST_sys_shmctl)      ( TId, UW, UW, UW, UW );
+
 #undef TID
 #undef UW
 
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 2066701..14e4c97 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -1317,6 +1317,373 @@
 
 
 /* ---------------------------------------------------------------------
+   Deal with a bunch of IPC related syscalls
+   ------------------------------------------------------------------ */
+
+/* ------ */
+
+void
+VG_(generic_PRE_sys_semop) ( ThreadId tid,
+                             UWord arg0, UWord arg1, UWord arg2 )
+{
+   /* int semop(int semid, struct sembuf *sops, unsigned nsops); */
+   PRE_MEM_READ( "semop(sops)", arg1, arg2 * sizeof(struct vki_sembuf) );
+}
+
+/* ------ */
+
+void
+VG_(generic_PRE_sys_semtimedop) ( ThreadId tid,
+                                  UWord arg0, UWord arg1,
+                                  UWord arg2, UWord arg3 )
+{
+   /* int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
+                     struct timespec *timeout); */
+   PRE_MEM_READ( "semtimedop(sops)", arg1, arg2 * sizeof(struct vki_sembuf) );
+   if (arg3 != 0)
+      PRE_MEM_READ( "semtimedop(timeout)", arg3, sizeof(struct vki_timespec) );
+}
+
+/* ------ */
+
+static
+UInt get_sem_count( Int semid )
+{
+  struct vki_semid_ds buf;
+  union vki_semun arg;
+  long res;
+
+  arg.buf = &buf;
+
+#ifdef __NR_semctl
+  res = VG_(do_syscall4)(__NR_semctl, semid, 0, VKI_IPC_STAT, *(UWord *)&arg);
+#else
+  res = VG_(do_syscall5)(__NR_ipc, 3 /* IPCOP_semctl */, semid, 0,
+                         VKI_IPC_STAT, (UWord)&arg);
+#endif
+  if ( VG_(is_kerror)(res) )
+    return 0;
+
+  return buf.sem_nsems;
+}
+
+void
+VG_(generic_PRE_sys_semctl) ( ThreadId tid,
+                              UWord arg0, UWord arg1,
+                              UWord arg2, UWord arg3 )
+{
+   /* int semctl(int semid, int semnum, int cmd, ...); */
+   union vki_semun arg = *(union vki_semun *)&arg3;
+   UInt nsems;
+   switch (arg2 /* cmd */) {
+   case VKI_IPC_INFO:
+   case VKI_SEM_INFO:
+   case VKI_IPC_INFO|VKI_IPC_64:
+   case VKI_SEM_INFO|VKI_IPC_64:
+      PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)",
+                     (Addr)arg.buf, sizeof(struct vki_seminfo) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_SEM_STAT:
+      PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
+                     (Addr)arg.buf, sizeof(struct vki_semid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_SEM_STAT|VKI_IPC_64:
+      PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
+                     (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
+                    (Addr)arg.buf, sizeof(struct vki_semid_ds) );
+      break;
+   case VKI_IPC_SET|VKI_IPC_64:
+      PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
+                    (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
+      break;
+   case VKI_GETALL:
+   case VKI_GETALL|VKI_IPC_64:
+      nsems = get_sem_count( arg0 );
+      PRE_MEM_WRITE( "semctl(IPC_GETALL, arg.array)",
+                     (Addr)arg.array, sizeof(unsigned short) * nsems );
+      break;
+   case VKI_SETALL:
+   case VKI_SETALL|VKI_IPC_64:
+      nsems = get_sem_count( arg0 );
+      PRE_MEM_READ( "semctl(IPC_SETALL, arg.array)",
+                    (Addr)arg.array, sizeof(unsigned short) * nsems );
+      break;
+   }
+}
+
+void
+VG_(generic_POST_sys_semctl) ( ThreadId tid,
+                               UWord res,
+                               UWord arg0, UWord arg1,
+                               UWord arg2, UWord arg3 )
+{
+   union vki_semun arg = *(union vki_semun *)&arg3;
+   UInt nsems;
+   switch (arg2 /* cmd */) {
+   case VKI_IPC_INFO:
+   case VKI_SEM_INFO:
+   case VKI_IPC_INFO|VKI_IPC_64:
+   case VKI_SEM_INFO|VKI_IPC_64:
+      POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_seminfo) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_SEM_STAT:
+      POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_SEM_STAT|VKI_IPC_64:
+      POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
+      break;
+   case VKI_GETALL:
+   case VKI_GETALL|VKI_IPC_64:
+      nsems = get_sem_count( arg0 );
+      POST_MEM_WRITE( (Addr)arg.array, sizeof(unsigned short) * nsems );
+      break;
+   }
+}
+
+/* ------ */
+
+void
+VG_(generic_PRE_sys_msgsnd) ( ThreadId tid,
+                              UWord arg0, UWord arg1,
+                              UWord arg2, UWord arg3 )
+{
+   /* int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); */
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
+   PRE_MEM_READ( "msgsnd(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   PRE_MEM_READ( "msgsnd(msgp->mtext)", (Addr)&msgp->mtext, arg2 );
+}
+
+/* ------ */
+
+void
+VG_(generic_PRE_sys_msgrcv) ( ThreadId tid,
+                              UWord arg0, UWord arg1, UWord arg2,
+                              UWord arg3, UWord arg4 )
+{
+   /* ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz,
+                     long msgtyp, int msgflg); */
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
+   PRE_MEM_WRITE( "msgrcv(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   PRE_MEM_WRITE( "msgrcv(msgp->mtext)", (Addr)&msgp->mtext, arg2 );
+}
+
+void
+VG_(generic_POST_sys_msgrcv) ( ThreadId tid,
+                               UWord res,
+                               UWord arg0, UWord arg1, UWord arg2,
+                               UWord arg3, UWord arg4 )
+{
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
+   POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   POST_MEM_WRITE( (Addr)&msgp->mtext, res );
+}
+
+/* ------ */
+
+void
+VG_(generic_PRE_sys_msgctl) ( ThreadId tid,
+                              UWord arg0, UWord arg1, UWord arg2 )
+{
+   /* int msgctl(int msqid, int cmd, struct msqid_ds *buf); */
+   switch (arg1 /* cmd */) {
+   case VKI_IPC_INFO:
+   case VKI_MSG_INFO:
+   case VKI_IPC_INFO|VKI_IPC_64:
+   case VKI_MSG_INFO|VKI_IPC_64:
+      PRE_MEM_WRITE( "msgctl(IPC_INFO, buf)",
+                     arg2, sizeof(struct vki_msginfo) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_MSG_STAT:
+      PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)",
+                     arg2, sizeof(struct vki_msqid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_MSG_STAT|VKI_IPC_64:
+      PRE_MEM_WRITE( "msgctl(IPC_STAT, arg.buf)",
+                     arg2, sizeof(struct vki_msqid64_ds) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)",
+                    arg2, sizeof(struct vki_msqid_ds) );
+      break;
+   case VKI_IPC_SET|VKI_IPC_64:
+      PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)",
+                    arg2, sizeof(struct vki_msqid64_ds) );
+      break;
+   }
+}
+
+void
+VG_(generic_POST_sys_msgctl) ( ThreadId tid,
+                               UWord res,
+                               UWord arg0, UWord arg1, UWord arg2 )
+{
+   switch (arg1 /* cmd */) {
+   case VKI_IPC_INFO:
+   case VKI_MSG_INFO:
+   case VKI_IPC_INFO|VKI_IPC_64:
+   case VKI_MSG_INFO|VKI_IPC_64:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_msginfo) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_MSG_STAT:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_msqid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_MSG_STAT|VKI_IPC_64:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_msqid64_ds) );
+      break;
+   }
+}
+
+/* ------ */
+
+static
+UInt get_shm_size ( Int shmid )
+{
+#ifdef __NR_shmctl
+   struct vki_shmid64_ds buf;
+   long __res = VG_(do_syscall3)(__NR_shmctl, shmid, VKI_IPC_STAT, (UWord)&buf);
+#else
+   struct vki_shmid_ds buf;
+   long __res = VG_(do_syscall5)(__NR_ipc, 24 /* IPCOP_shmctl */, shmid,
+                                 VKI_IPC_STAT, 0, (UWord)&buf);
+#endif
+   if ( VG_(is_kerror) ( __res ) )
+      return 0;
+ 
+   return buf.shm_segsz;
+}
+
+UWord
+VG_(generic_PRE_sys_shmat) ( ThreadId tid,
+                             UWord arg0, UWord arg1, UWord arg2 )
+{
+   /* void *shmat(int shmid, const void *shmaddr, int shmflg); */
+   UInt segmentSize = get_shm_size ( arg0 );
+   if (arg1 == 0)
+      arg1 = VG_(find_map_space)(0, segmentSize, True);
+   else if (!VG_(valid_client_addr)(arg1, segmentSize, tid, "shmat"))
+      arg1 = 0;
+   return arg1;
+}
+
+void
+VG_(generic_POST_sys_shmat) ( ThreadId tid,
+                              UWord res,
+                              UWord arg0, UWord arg1, UWord arg2 )
+{
+   UInt segmentSize = get_shm_size ( arg0 );
+   if ( segmentSize > 0 ) {
+      UInt prot = VKI_PROT_READ|VKI_PROT_WRITE;
+      /* we don't distinguish whether it's read-only or
+       * read-write -- it doesn't matter really. */
+      VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False );
+
+      if (!(arg2 & 010000)) /* = SHM_RDONLY */
+         prot &= ~VKI_PROT_WRITE;
+      VG_(map_segment)(res, segmentSize, prot, SF_SHARED|SF_SHM);
+   }
+}
+
+/* ------ */
+
+Bool
+VG_(generic_PRE_sys_shmdt) ( ThreadId tid, UWord arg0 )
+{
+   /* int shmdt(const void *shmaddr); */
+   return VG_(valid_client_addr)(arg0, 1, tid, "shmdt");
+}
+
+void
+VG_(generic_POST_sys_shmdt) ( ThreadId tid, UWord res, UWord arg0 )
+{
+   Segment *s = VG_(find_segment)(arg0);
+
+   if (s != NULL && (s->flags & SF_SHM) && VG_(seg_contains)(s, arg0, 1)) {
+      VG_TRACK( die_mem_munmap, s->addr, s->len );
+      VG_(unmap_range)(s->addr, s->len);
+   }
+}
+/* ------ */
+
+void
+VG_(generic_PRE_sys_shmctl) ( ThreadId tid,
+                              UWord arg0, UWord arg1, UWord arg2 )
+{
+   /* int shmctl(int shmid, int cmd, struct shmid_ds *buf); */
+   switch (arg1 /* cmd */) {
+   case VKI_IPC_INFO:
+      PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
+                     arg2, sizeof(struct vki_shminfo) );
+      break;
+   case VKI_IPC_INFO|VKI_IPC_64:
+      PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
+                     arg2, sizeof(struct vki_shminfo64) );
+      break;
+   case VKI_SHM_INFO:
+   case VKI_SHM_INFO|VKI_IPC_64:
+      PRE_MEM_WRITE( "shmctl(SHM_INFO, buf)",
+                     arg2, sizeof(struct vki_shm_info) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_SHM_STAT:
+      PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)",
+                     arg2, sizeof(struct vki_shmid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_SHM_STAT|VKI_IPC_64:
+      PRE_MEM_WRITE( "shmctl(IPC_STAT, arg.buf)",
+                     arg2, sizeof(struct vki_shmid64_ds) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
+                    arg2, sizeof(struct vki_shmid_ds) );
+      break;
+   case VKI_IPC_SET|VKI_IPC_64:
+      PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
+                    arg2, sizeof(struct vki_shmid64_ds) );
+      break;
+   }
+}
+
+void
+VG_(generic_POST_sys_shmctl) ( ThreadId tid,
+                               UWord res,
+                               UWord arg0, UWord arg1, UWord arg2 )
+{
+   switch (arg1 /* cmd */) {
+   case VKI_IPC_INFO:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo) );
+      break;
+   case VKI_IPC_INFO|VKI_IPC_64:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo64) );
+      break;
+   case VKI_SHM_INFO:
+   case VKI_SHM_INFO|VKI_IPC_64:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_shm_info) );
+      break;
+   case VKI_IPC_STAT:
+   case VKI_SHM_STAT:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_shmid_ds) );
+      break;
+   case VKI_IPC_STAT|VKI_IPC_64:
+   case VKI_SHM_STAT|VKI_IPC_64:
+      POST_MEM_WRITE( arg2, sizeof(struct vki_shmid64_ds) );
+      break;
+   }
+}
+
+
+/* ---------------------------------------------------------------------
    The Main Entertainment ... syscall wrappers
    ------------------------------------------------------------------ */
 
diff --git a/coregrind/x86-linux/syscalls.c b/coregrind/x86-linux/syscalls.c
index a7120d5..1fe922d 100644
--- a/coregrind/x86-linux/syscalls.c
+++ b/coregrind/x86-linux/syscalls.c
@@ -726,35 +726,6 @@
    }
 }
 
-static
-UInt get_shm_size ( Int shmid )
-{
-   struct vki_shmid_ds buf;
-   long __res = VG_(do_syscall5)(__NR_ipc, 24 /* IPCOP_shmctl */, shmid,
-                                 VKI_IPC_STAT, 0, (UWord)&buf);
-    if ( VG_(is_kerror) ( __res ) )
-       return 0;
- 
-   return buf.shm_segsz;
-}
-
-static
-UInt get_sem_count( Int semid )
-{
-  struct vki_semid_ds buf;
-  union vki_semun arg;
-  long res;
-
-  arg.buf = &buf;
-  
-  res = VG_(do_syscall5)(__NR_ipc, 3 /* IPCOP_semctl */, semid, 0,
-                         VKI_IPC_STAT, (UWord)&arg);
-  if ( VG_(is_kerror)(res) )
-    return 0;
-
-  return buf.sem_nsems;
-}
-
 // XXX: this duplicates a function in coregrind/vg_syscalls.c, yuk
 static Addr deref_Addr ( ThreadId tid, Addr a, Char* s )
 {
@@ -774,146 +745,40 @@
 
    switch (ARG1 /* call */) {
    case VKI_SEMOP:
-      PRE_MEM_READ( "semop(sops)", ARG5, ARG3 * sizeof(struct vki_sembuf) );
+      VG_(generic_PRE_sys_semop)( tid, ARG2, ARG5, ARG3 );
       /* tst->sys_flags |= MayBlock; */
       break;
    case VKI_SEMGET:
       break;
    case VKI_SEMCTL:
    {
-      union vki_semun *arg = (union vki_semun *)ARG5;
-      switch (ARG4 /* cmd */) {
-      case VKI_IPC_INFO:
-      case VKI_SEM_INFO:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->__buf, "semctl(IPC_INFO, arg)" );
-	 PRE_MEM_WRITE( "semctl(IPC_INFO, arg->buf)", buf, 
-			sizeof(struct vki_seminfo) );
-	 break;
-      }
-      case VKI_IPC_STAT:
-      case VKI_SEM_STAT:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(IPC_STAT, arg)" );
-	 PRE_MEM_WRITE( "semctl(IPC_STAT, arg->buf)", buf, 
-			sizeof(struct vki_semid_ds) );
-	 break;
-      }
-      case VKI_IPC_SET:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(IPC_SET, arg)" );
-	 PRE_MEM_READ( "semctl(IPC_SET, arg->buf)", buf, 
-			sizeof(struct vki_semid_ds) );
-	 break;
-      }
-      case VKI_GETALL:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(IPC_GETALL, arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 PRE_MEM_WRITE( "semctl(IPC_GETALL, arg->array)", array, 
-			sizeof(short) * nsems );
-	 break;
-      }
-      case VKI_SETALL:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(IPC_SETALL, arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 PRE_MEM_READ( "semctl(IPC_SETALL, arg->array)", array, 
-			sizeof(short) * nsems );
-	 break;
-      }
-      case VKI_SETVAL:
-      {
-	 PRE_MEM_READ( "semctl(IPC_SETVAL, arg->array)",
-                        (Addr)&arg->val, sizeof(arg->val) );
-	 break;
-      }
-      case VKI_IPC_INFO|VKI_IPC_64:
-      case VKI_SEM_INFO|VKI_IPC_64:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->__buf, "semctl(IPC_INFO, arg)" );
-	 PRE_MEM_WRITE( "semctl(IPC_INFO, arg->buf)", buf, 
-			sizeof(struct vki_seminfo) );
-	 break;
-      }
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_SEM_STAT|VKI_IPC_64:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(IPC_STAT, arg)" );
-	 PRE_MEM_WRITE( "semctl(IPC_STAT, arg->buf)", buf, 
-			sizeof(struct vki_semid64_ds) );
-	 break;
-      }
-      case VKI_IPC_SET|VKI_IPC_64:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(IPC_SET, arg)" );
-	 PRE_MEM_READ( "semctl(IPC_SET, arg->buf)", buf, 
-			sizeof(struct vki_semid64_ds) );
-	 break;
-      }
-      case VKI_GETALL|VKI_IPC_64:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(IPC_GETALL, arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 PRE_MEM_WRITE( "semctl(IPC_GETALL, arg->array)", array, 
-			sizeof(short) * nsems );
-	 break;
-      }
-      case VKI_SETALL|VKI_IPC_64:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(IPC_SETALL, arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 PRE_MEM_READ( "semctl(IPC_SETALL, arg->array)", array, 
-			sizeof(short) * nsems );
-	 break;
-      }
-      case VKI_SETVAL|VKI_IPC_64:
-      {
-	 PRE_MEM_READ( "semctl(IPC_SETVAL, arg->array)",
-                        (Addr)&arg->val, sizeof(arg->val) );
-	 break;
-      }
-      default:
-	 break;
-      }
+      UWord arg = deref_Addr( tid, ARG5, "semctl(arg)" );
+      VG_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg );
       break;
    }
    case VKI_SEMTIMEDOP:
-      PRE_MEM_READ( "semtimedop(sops)", ARG5, 
-		     ARG3 * sizeof(struct vki_sembuf) );
-      if (ARG6 != 0)
-         PRE_MEM_READ( "semtimedop(timeout)", ARG6, 
-                        sizeof(struct vki_timespec) );
+      VG_(generic_PRE_sys_semtimedop)( tid, ARG2, ARG5, ARG3, ARG6 );
       /* tst->sys_flags |= MayBlock; */
       break;
    case VKI_MSGSND:
-   {
-      struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG5;
-      Int msgsz = ARG3;
-
-      PRE_MEM_READ( "msgsnd(msgp->mtype)", 
-		     (Addr)&msgp->mtype, sizeof(msgp->mtype) );
-      PRE_MEM_READ( "msgsnd(msgp->mtext)", 
-		     (Addr)msgp->mtext, msgsz );
-
+      VG_(generic_PRE_sys_msgsnd)( tid, ARG2, ARG5, ARG3, ARG4 );
       /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
             tst->sys_flags |= MayBlock;
       */
       break;
-   }
    case VKI_MSGRCV:
    {
-      struct vki_msgbuf *msgp;
-      Int msgsz = ARG3;
+      Addr msgp;
+      Word msgtyp;
  
-      msgp = (struct vki_msgbuf *)deref_Addr( tid,
-					  (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
-					  "msgrcv(msgp)" );
+      msgp = deref_Addr( tid,
+			 (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
+			 "msgrcv(msgp)" );
+      msgtyp = deref_Addr( tid,
+			   (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgtyp),
+			   "msgrcv(msgp)" );
 
-      PRE_MEM_WRITE( "msgrcv(msgp->mtype)", 
-		     (Addr)&msgp->mtype, sizeof(msgp->mtype) );
-      PRE_MEM_WRITE( "msgrcv(msgp->mtext)", 
-		     (Addr)msgp->mtext, msgsz );
+      VG_(generic_PRE_sys_msgrcv)( tid, ARG2, msgp, ARG3, msgtyp, ARG4 );
 
       /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
             tst->sys_flags |= MayBlock;
@@ -923,102 +788,23 @@
    case VKI_MSGGET:
       break;
    case VKI_MSGCTL:
-   {
-      switch (ARG3 /* cmd */) {
-      case VKI_IPC_INFO:
-      case VKI_MSG_INFO:
-	 PRE_MEM_WRITE( "msgctl(IPC_INFO, buf)", ARG5, 
-			sizeof(struct vki_msginfo) );
-	 break;
-      case VKI_IPC_STAT:
-      case VKI_MSG_STAT:
-	 PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)", ARG5, 
-			sizeof(struct vki_msqid_ds) );
-	 break;
-      case VKI_IPC_SET:
-	 PRE_MEM_READ( "msgctl(IPC_SET, buf)", ARG5, 
-			sizeof(struct vki_msqid_ds) );
-	 break;
-      case VKI_IPC_INFO|VKI_IPC_64:
-      case VKI_MSG_INFO|VKI_IPC_64:
-	 PRE_MEM_WRITE( "msgctl(IPC_INFO, buf)", ARG5, 
-			sizeof(struct vki_msginfo) );
-	 break;
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_MSG_STAT|VKI_IPC_64:
-	 PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)", ARG5, 
-			sizeof(struct vki_msqid64_ds) );
-	 break;
-      case VKI_IPC_SET|VKI_IPC_64:
-	 PRE_MEM_READ( "msgctl(IPC_SET, buf)", ARG5, 
-			sizeof(struct vki_msqid64_ds) );
-	 break;
-      default:
-	 break;
-      }
+      VG_(generic_PRE_sys_msgctl)( tid, ARG2, ARG3, ARG5 );
       break;
-   }
    case VKI_SHMAT:
-   {
-      UInt shmid = ARG2;
-      UInt segmentSize = get_shm_size ( shmid );
-      
-      /* If they didn't ask for a particular address, then place it
-	 like an mmap. */
+      PRE_MEM_WRITE( "shmat(raddr)", ARG4, sizeof(Addr) );
+      ARG5 = VG_(generic_PRE_sys_shmat)( tid, ARG2, ARG5, ARG3 );
       if (ARG5 == 0)
-	 ARG5 = VG_(find_map_space)(0, segmentSize, True);
-      else if (!VG_(valid_client_addr)(ARG5, segmentSize, tid, "shmat"))
-	 SET_RESULT( -VKI_EINVAL );
+         SET_RESULT( -VKI_EINVAL );
       break;
-   }
    case VKI_SHMDT:
-      if (!VG_(valid_client_addr)(ARG5, 1, tid, "shmdt"))
+      if (!VG_(generic_PRE_sys_shmdt)(tid, ARG5))
 	 SET_RESULT( -VKI_EINVAL );
       break;
    case VKI_SHMGET:
       break;
    case VKI_SHMCTL: /* IPCOP_shmctl */
-   {
-      switch (ARG3 /* cmd */) {
-      case VKI_IPC_INFO:
-	 PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", ARG5, 
-			sizeof(struct vki_shminfo) );
-	 break;
-      case VKI_SHM_INFO:
-	 PRE_MEM_WRITE( "shmctl(SHM_INFO, buf)", ARG5, 
-			sizeof(struct vki_shm_info) );
-	 break;
-      case VKI_IPC_STAT:
-      case VKI_SHM_STAT:
-	 PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)", ARG5, 
-			sizeof(struct vki_shmid_ds) );
-	 break;
-      case VKI_IPC_SET:
-	 PRE_MEM_READ( "shmctl(IPC_SET, buf)", ARG5, 
-			sizeof(struct vki_shmid_ds) );
-	 break;
-      case VKI_IPC_INFO|VKI_IPC_64:
-	 PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", ARG5, 
-			sizeof(struct vki_shminfo64) );
-	 break;
-      case VKI_SHM_INFO|VKI_IPC_64:
-	 PRE_MEM_WRITE( "shmctl(SHM_INFO, buf)", ARG5, 
-			sizeof(struct vki_shm_info) );
-	 break;
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_SHM_STAT|VKI_IPC_64:
-	 PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)", ARG5, 
-			sizeof(struct vki_shmid64_ds) );
-	 break;
-      case VKI_IPC_SET|VKI_IPC_64:
-	 PRE_MEM_READ( "shmctl(IPC_SET, buf)", ARG5, 
-			sizeof(struct vki_shmid_ds) );
-	 break;
-      default:
-	 break;
-      }
+      VG_(generic_PRE_sys_shmctl)( tid, ARG2, ARG3, ARG5 );
       break;
-   }
    default:
       VG_(message)(Vg_DebugMsg, "FATAL: unhandled syscall(ipc) %d", ARG1 );
       VG_(core_panic)("... bye!\n");
@@ -1034,53 +820,8 @@
       break;
    case VKI_SEMCTL:
    {
-      union vki_semun *arg = (union vki_semun *)ARG5;
-      switch (ARG4 /* cmd */) {
-      case VKI_IPC_INFO:
-      case VKI_SEM_INFO:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->__buf, "semctl(arg)" );
-	 POST_MEM_WRITE( buf, sizeof(struct vki_seminfo) );
-	 break;
-      }
-      case VKI_IPC_STAT:
-      case VKI_SEM_STAT:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(arg)" );
-	 POST_MEM_WRITE( buf, sizeof(struct vki_semid_ds) );
-	 break;
-      }
-      case VKI_GETALL:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 POST_MEM_WRITE( array, sizeof(short) * nsems );
-	 break;
-      }
-      case VKI_IPC_INFO|VKI_IPC_64:
-      case VKI_SEM_INFO|VKI_IPC_64:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->__buf, "semctl(arg)" );
-	 POST_MEM_WRITE( buf, sizeof(struct vki_seminfo) );
-	 break;
-      }
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_SEM_STAT|VKI_IPC_64:
-      {
-         Addr buf = deref_Addr( tid, (Addr)&arg->buf, "semctl(arg)" );
-	 POST_MEM_WRITE( buf, sizeof(struct vki_semid64_ds) );
-	 break;
-      }
-      case VKI_GETALL|VKI_IPC_64:
-      {
-         Addr array = deref_Addr( tid, (Addr)&arg->array, "semctl(arg)" );
-         UInt nsems = get_sem_count( ARG2 );
-	 POST_MEM_WRITE( array, sizeof(short) * nsems );
-	 break;
-      }
-      default:
-	 break;
-      }
+      UWord arg = deref_Addr( tid, ARG5, "semctl(arg)" );
+      VG_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg );
       break;
    }
    case VKI_SEMTIMEDOP:
@@ -1088,114 +829,47 @@
       break;
    case VKI_MSGRCV:
    {
-      struct vki_msgbuf *msgp;
- 
-      msgp = (struct vki_msgbuf *)deref_Addr( tid,
-					  (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
-					  "msgrcv(msgp)" );
-      if ( RES > 0 ) {
-	 POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) );
-	 POST_MEM_WRITE( (Addr)msgp->mtext, RES );
-      }
+      Addr msgp;
+      Word msgtyp;
+
+      msgp = deref_Addr( tid,
+			 (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
+			 "msgrcv(msgp)" );
+      msgtyp = deref_Addr( tid,
+			   (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgtyp),
+			   "msgrcv(msgp)" );
+
+      VG_(generic_POST_sys_msgrcv)( tid, RES, ARG2, msgp, ARG3, msgtyp, ARG4 );
       break;
    }
    case VKI_MSGGET:
       break;
    case VKI_MSGCTL:
-   {
-      switch (ARG3 /* cmd */) {
-      case VKI_IPC_INFO:
-      case VKI_MSG_INFO:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_msginfo) );
-	 break;
-      case VKI_IPC_STAT:
-      case VKI_MSG_STAT:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_msqid_ds) );
-	 break;
-      case VKI_IPC_SET:
-	 break;
-      case VKI_IPC_INFO|VKI_IPC_64:
-      case VKI_MSG_INFO|VKI_IPC_64:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_msginfo) );
-	 break;
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_MSG_STAT|VKI_IPC_64:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_msqid64_ds) );
-	 break;
-      case VKI_IPC_SET|VKI_IPC_64:
-	 break;
-      default:
-	 break;
-      }
+      VG_(generic_POST_sys_msgctl)( tid, RES, ARG2, ARG3, ARG5 );
       break;
-   }
    case VKI_SHMAT:
    {
-      Int shmid = ARG2;
-      Int shmflag = ARG3;
       Addr addr;
 
       /* force readability. before the syscall it is
        * indeed uninitialized, as can be seen in
        * glibc/sysdeps/unix/sysv/linux/shmat.c */
-      POST_MEM_WRITE( ARG4, sizeof( ULong ) );
+      POST_MEM_WRITE( ARG4, sizeof( Addr ) );
 
       addr = deref_Addr ( tid, ARG4, "shmat(addr)" );
       if ( addr > 0 ) { 
-	 UInt segmentSize = get_shm_size ( shmid );
-	 if ( segmentSize > 0 ) {
-	    UInt prot = VKI_PROT_READ|VKI_PROT_WRITE;
-	    /* we don't distinguish whether it's read-only or
-	     * read-write -- it doesn't matter really. */
-	    VG_TRACK( new_mem_mmap, addr, segmentSize, True, True, False );
-
-	    if (!(shmflag & 010000)) /* = SHM_RDONLY */
-	       prot &= ~VKI_PROT_WRITE;
-	    VG_(map_segment)(addr, segmentSize, prot, SF_SHARED|SF_SHM);
-	 }
+         VG_(generic_POST_sys_shmat)( tid, addr, ARG2, ARG5, ARG3 );
       }
       break;
    }
    case VKI_SHMDT:
-   {
-      Segment *s = VG_(find_segment)(ARG5);
-
-      if (s != NULL && (s->flags & SF_SHM) && VG_(seg_contains)(s, ARG5, 1)) {
-	 VG_TRACK( die_mem_munmap, s->addr, s->len );
-	 VG_(unmap_range)(s->addr, s->len);
-      }
+      VG_(generic_POST_sys_shmdt)( tid, RES, ARG5 );
       break;
-   }
    case VKI_SHMGET:
       break;
    case VKI_SHMCTL:
-   {
-      switch (ARG3 /* cmd */) {
-      case VKI_IPC_INFO:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shminfo) );
-	 break;
-      case VKI_SHM_INFO:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shm_info) );
-	 break;
-      case VKI_IPC_STAT:
-      case VKI_SHM_STAT:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shmid_ds) );
-	 break;
-      case VKI_IPC_INFO|VKI_IPC_64:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shminfo64) );
-	 break;
-      case VKI_SHM_INFO|VKI_IPC_64:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shm_info) );
-	 break;
-      case VKI_IPC_STAT|VKI_IPC_64:
-      case VKI_SHM_STAT|VKI_IPC_64:
-	 POST_MEM_WRITE( ARG5, sizeof(struct vki_shmid64_ds) );
-	 break;
-      default:
-	 break;
-      }
+      VG_(generic_POST_sys_shmctl)( tid, RES, ARG2, ARG3, ARG5 );
       break;
-   }
    default:
       VG_(message)(Vg_DebugMsg,
 		   "FATAL: unhandled syscall(ipc) %d",
diff --git a/include/amd64-linux/vki_arch.h b/include/amd64-linux/vki_arch.h
index 2cda2f6..018df7e 100644
--- a/include/amd64-linux/vki_arch.h
+++ b/include/amd64-linux/vki_arch.h
@@ -520,6 +520,87 @@
 typedef void vki_modify_ldt_t;
 
 //----------------------------------------------------------------------
+// From linux-2.6.11.2/include/asm-x86_64/ipcbuf.h
+//----------------------------------------------------------------------
+
+struct vki_ipc64_perm
+{
+	__vki_kernel_key_t	key;
+	__vki_kernel_uid32_t	uid;
+	__vki_kernel_gid32_t	gid;
+	__vki_kernel_uid32_t	cuid;
+	__vki_kernel_gid32_t	cgid;
+	__vki_kernel_mode_t	mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.11.2/include/asm-x86_64/sembuf.h
+//----------------------------------------------------------------------
+
+struct vki_semid64_ds {
+	struct vki_ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__vki_kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__vki_kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.11.2/include/asm-x86_64/msgbuf.h
+//----------------------------------------------------------------------
+
+struct vki_msqid64_ds {
+	struct vki_ipc64_perm msg_perm;
+	__vki_kernel_time_t msg_stime;	/* last msgsnd time */
+	__vki_kernel_time_t msg_rtime;	/* last msgrcv time */
+	__vki_kernel_time_t msg_ctime;	/* last change time */
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__vki_kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__vki_kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.11.2/include/asm-x86_64/shmbuf.h
+//----------------------------------------------------------------------
+
+struct vki_shmid64_ds {
+	struct vki_ipc64_perm	shm_perm;	/* operation perms */
+	vki_size_t		shm_segsz;	/* size of segment (bytes) */
+	__vki_kernel_time_t	shm_atime;	/* last attach time */
+	__vki_kernel_time_t	shm_dtime;	/* last detach time */
+	__vki_kernel_time_t	shm_ctime;	/* last change time */
+	__vki_kernel_pid_t	shm_cpid;	/* pid of creator */
+	__vki_kernel_pid_t	shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct vki_shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+//----------------------------------------------------------------------
 // And that's it!
 //----------------------------------------------------------------------