]> granicus.if.org Git - strace/blobdiff - file.c
Check HAVE_LONG_LONG_OFF_T when printing offset
[strace] / file.c
diff --git a/file.c b/file.c
index 3ec97e314b3d0c67b633aefd4b9a6829d5ee4b0e..db024ef83891d3ffde0784f7e9ec13eb22fe0895 100644 (file)
--- a/file.c
+++ b/file.c
 #include "defs.h"
 
 #include <dirent.h>
-#ifdef linux
-#define dirent kernel_dirent
-#define dirent64 kernel_dirent64
-#include <linux/types.h>
-#include <linux/dirent.h>
-#undef dirent
+
+#ifdef LINUX
+struct kernel_dirent {
+       unsigned long   d_ino;
+       unsigned long   d_off;
+       unsigned short  d_reclen;
+       char            d_name[1];
+};
 #else
-#define kernel_dirent dirent
+# define kernel_dirent dirent
 #endif
 
-#ifdef linux
+#ifdef LINUX
 #  ifdef LINUXSPARC
 struct stat {
        unsigned short  st_dev;
@@ -64,6 +66,24 @@ struct stat {
        int             st_blocks;
        unsigned int    __unused4[2];
 };
+#if defined(SPARC64)
+struct stat_sparc64 {
+       unsigned int    st_dev;
+       unsigned long   st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_rdev;
+       long            st_size;
+       long            st_atime;
+       long            st_mtime;
+       long            st_ctime;
+       long            st_blksize;
+       long            st_blocks;
+       unsigned long   __unused4[2];
+};
+#endif /* SPARC64 */
 #    define stat kernel_stat
 #    include <asm/stat.h>
 #    undef stat
@@ -106,11 +126,21 @@ struct stat {
 #    define off_t off_t
 #    define loff_t loff_t
 #  endif
+#  ifdef HPPA  /* asm-parisc/stat.h defines stat64 */
+#    undef stat64
+#  endif
 #  define stat libc_stat
 #  define stat64 libc_stat64
 #  include <sys/stat.h>
 #  undef stat
 #  undef stat64
+   /* These might be macros. */
+#  undef st_atime
+#  undef st_mtime
+#  undef st_ctime
+#  ifdef HPPA
+#    define stat64 hpux_stat64
+#  endif
 #else
 #  include <sys/stat.h>
 #endif
@@ -125,12 +155,44 @@ struct stat {
 #include <sys/vfs.h>
 #endif
 
+#ifdef HAVE_LINUX_XATTR_H
+#include <linux/xattr.h>
+#elif defined linux
+#define XATTR_CREATE 1
+#define XATTR_REPLACE 2
+#endif
+
 #ifdef FREEBSD
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #endif
 
+#if _LFS64_LARGEFILE && (defined(LINUX) || defined(SVR4))
+# ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+# else
+#  define PRId64 "lld"
+#  define PRIu64 "llu"
+# endif
+#endif
+
+#if HAVE_LONG_LONG_OFF_T
+/*
+ * Ugly hacks for systems that have typedef long long off_t
+ */
+
+#define stat64 stat
+#define HAVE_STAT64 1  /* Ugly hack */
+
+#define        sys_stat64      sys_stat
+#define sys_fstat64    sys_fstat
+#define sys_lstat64    sys_lstat
+#define sys_lseek64    sys_lseek
+#define sys_truncate64 sys_truncate
+#define sys_ftruncate64        sys_ftruncate
+#endif
+
 #ifdef MAJOR_IN_SYSMACROS
 #include <sys/sysmacros.h>
 #endif
@@ -147,21 +209,23 @@ struct stat {
 #include <ustat.h>
 #endif
 
-/*
- * This is a really dirty trick but it should always work.  Traditional
- * Unix says r/w/rw are 0/1/2, so we make them true flags 1/2/3 by
- * adding 1.  Just remember to add 1 to any arg decoded with openmodes.
- */
-struct xlat openmodes[] = {
-       { O_RDWR+1,     "O_RDWR"        },
-       { O_RDONLY+1,   "O_RDONLY"      },
-       { O_WRONLY+1,   "O_WRONLY"      },
-       { O_NONBLOCK,   "O_NONBLOCK"    },
-       { O_APPEND,     "O_APPEND"      },
+const struct xlat open_access_modes[] = {
+       { O_RDONLY,     "O_RDONLY"      },
+       { O_WRONLY,     "O_WRONLY"      },
+       { O_RDWR,       "O_RDWR"        },
+#ifdef O_ACCMODE
+       { O_ACCMODE,    "O_ACCMODE"     },
+#endif
+       { 0,            NULL            },
+};
+
+const struct xlat open_mode_flags[] = {
        { O_CREAT,      "O_CREAT"       },
-       { O_TRUNC,      "O_TRUNC"       },
        { O_EXCL,       "O_EXCL"        },
        { O_NOCTTY,     "O_NOCTTY"      },
+       { O_TRUNC,      "O_TRUNC"       },
+       { O_APPEND,     "O_APPEND"      },
+       { O_NONBLOCK,   "O_NONBLOCK"    },
 #ifdef O_SYNC
        { O_SYNC,       "O_SYNC"        },
 #endif
@@ -174,7 +238,7 @@ struct xlat openmodes[] = {
 #ifdef O_RSYNC
        { O_RSYNC,      "O_RSYNC"       },
 #endif
-#ifdef O_NDELAY
+#if defined(O_NDELAY) && (O_NDELAY != O_NONBLOCK)
        { O_NDELAY,     "O_NDELAY"      },
 #endif
 #ifdef O_PRIV
@@ -184,15 +248,30 @@ struct xlat openmodes[] = {
        { O_DIRECT,     "O_DIRECT"      },
 #endif
 #ifdef O_LARGEFILE
-       { O_LARGEFILE,  "O_LARGEFILE"   },
+# if O_LARGEFILE == 0          /* biarch platforms in 64-bit mode */
+#  undef O_LARGEFILE
+#  ifdef SPARC64
+#   define O_LARGEFILE 0x40000
+#  elif defined X86_64 || defined S390X
+#   define O_LARGEFILE 0100000
+#  endif
+# endif
+# ifdef O_LARGEFILE
+       { O_LARGEFILE,  "O_LARGEFILE"   },
+# endif
 #endif
 #ifdef O_DIRECTORY
-       { O_DIRECTORY,  "O_DIRECTORY"   },
+       { O_DIRECTORY,  "O_DIRECTORY"   },
 #endif
 #ifdef O_NOFOLLOW
-       { O_NOFOLLOW,   "O_NOFOLLOW"    },
+       { O_NOFOLLOW,   "O_NOFOLLOW"    },
+#endif
+#ifdef O_NOATIME
+       { O_NOATIME,    "O_NOATIME"     },
+#endif
+#ifdef O_CLOEXEC
+       { O_CLOEXEC,    "O_CLOEXEC"     },
 #endif
-
 #ifdef FNDELAY
        { FNDELAY,      "FNDELAY"       },
 #endif
@@ -231,7 +310,7 @@ struct xlat openmodes[] = {
 #endif
 #ifdef FNOCTTY
        { FNOCTTY,      "FNOCTTY"       },
-#endif 
+#endif
 #ifdef O_SHLOCK
        { O_SHLOCK,     "O_SHLOCK"      },
 #endif
@@ -241,25 +320,108 @@ struct xlat openmodes[] = {
        { 0,            NULL            },
 };
 
-int
-sys_open(tcp)
-struct tcb *tcp;
+#ifdef LINUX
+
+#ifndef AT_FDCWD
+# define AT_FDCWD                -100
+#endif
+
+/* The fd is an "int", so when decoding x86 on x86_64, we need to force sign
+ * extension to get the right value.  We do this by declaring fd as int here.
+ */
+static void
+print_dirfd(struct tcb *tcp, int fd)
+{
+       if (fd == AT_FDCWD)
+               tprints("AT_FDCWD, ");
+       else {
+               printfd(tcp, fd);
+               tprints(", ");
+       }
+}
+#endif
+
+/*
+ * low bits of the open(2) flags define access mode,
+ * other bits are real flags.
+ */
+const char *
+sprint_open_modes(mode_t flags)
+{
+       static char outstr[(1 + ARRAY_SIZE(open_mode_flags)) * sizeof("O_LARGEFILE")];
+       char *p;
+       char sep;
+       const char *str;
+       const struct xlat *x;
+
+       sep = ' ';
+       p = stpcpy(outstr, "flags");
+       str = xlookup(open_access_modes, flags & 3);
+       if (str) {
+               *p++ = sep;
+               p = stpcpy(p, str);
+               flags &= ~3;
+               if (!flags)
+                       return outstr;
+               sep = '|';
+       }
+
+       for (x = open_mode_flags; x->str; x++) {
+               if ((flags & x->val) == x->val) {
+                       *p++ = sep;
+                       p = stpcpy(p, x->str);
+                       flags &= ~x->val;
+                       if (!flags)
+                               return outstr;
+                       sep = '|';
+               }
+       }
+       /* flags is still nonzero */
+       *p++ = sep;
+       sprintf(p, "%#x", flags);
+       return outstr;
+}
+
+void
+tprint_open_modes(mode_t flags)
+{
+       tprints(sprint_open_modes(flags) + sizeof("flags"));
+}
+
+static int
+decode_open(struct tcb *tcp, int offset)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               printpath(tcp, tcp->u_arg[offset]);
+               tprints(", ");
                /* flags */
-               printflags(openmodes, tcp->u_arg[1] + 1);
-               if (tcp->u_arg[1] & O_CREAT) {
+               tprint_open_modes(tcp->u_arg[offset + 1]);
+               if (tcp->u_arg[offset + 1] & O_CREAT) {
                        /* mode */
-                       tprintf(", %#lo", tcp->u_arg[2]);
+                       tprintf(", %#lo", tcp->u_arg[offset + 2]);
                }
        }
        return 0;
 }
 
+int
+sys_open(struct tcb *tcp)
+{
+       return decode_open(tcp, 0);
+}
+
+#ifdef LINUX
+int
+sys_openat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_open(tcp, 1);
+}
+#endif
+
 #ifdef LINUXSPARC
-struct xlat openmodessol[] = {
+static const struct xlat openmodessol[] = {
        { 0,            "O_RDWR"        },
        { 1,            "O_RDONLY"      },
        { 2,            "O_WRONLY"      },
@@ -278,14 +440,13 @@ struct xlat openmodessol[] = {
 };
 
 int
-solaris_open(tcp)
-struct tcb *tcp;
+solaris_open(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
                /* flags */
-               printflags(openmodessol, tcp->u_arg[1] + 1);
+               printflags(openmodessol, tcp->u_arg[1] + 1, "O_???");
                if (tcp->u_arg[1] & 0x100) {
                        /* mode */
                        tprintf(", %#lo", tcp->u_arg[2]);
@@ -297,8 +458,7 @@ struct tcb *tcp;
 #endif
 
 int
-sys_creat(tcp)
-struct tcb *tcp;
+sys_creat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
@@ -307,7 +467,7 @@ struct tcb *tcp;
        return 0;
 }
 
-static struct xlat access_flags[] = {
+static const struct xlat access_flags[] = {
        { F_OK,         "F_OK",         },
        { R_OK,         "R_OK"          },
        { W_OK,         "W_OK"          },
@@ -321,21 +481,35 @@ static struct xlat access_flags[] = {
        { 0,            NULL            },
 };
 
-int
-sys_access(tcp)
-struct tcb *tcp;
+static int
+decode_access(struct tcb *tcp, int offset)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-               printflags(access_flags, tcp->u_arg[1]);
+               printpath(tcp, tcp->u_arg[offset]);
+               tprints(", ");
+               printflags(access_flags, tcp->u_arg[offset + 1], "?_OK");
        }
        return 0;
 }
 
 int
-sys_umask(tcp)
-struct tcb *tcp;
+sys_access(struct tcb *tcp)
+{
+       return decode_access(tcp, 0);
+}
+
+#ifdef LINUX
+int
+sys_faccessat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_access(tcp, 1);
+}
+#endif
+
+int
+sys_umask(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%#lo", tcp->u_arg[0]);
@@ -343,124 +517,172 @@ struct tcb *tcp;
        return RVAL_OCTAL;
 }
 
-static struct xlat whence[] = {
+static const struct xlat whence[] = {
        { SEEK_SET,     "SEEK_SET"      },
        { SEEK_CUR,     "SEEK_CUR"      },
        { SEEK_END,     "SEEK_END"      },
        { 0,            NULL            },
 };
 
+#ifndef HAVE_LONG_LONG_OFF_T
+#if defined (LINUX_MIPSN32)
+int
+sys_lseek(struct tcb *tcp)
+{
+       long long offset;
+       int _whence;
+
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               offset = tcp->ext_arg[1];
+               _whence = tcp->u_arg[2];
+               if (_whence == SEEK_SET)
+                       tprintf("%llu, ", offset);
+               else
+                       tprintf("%lld, ", offset);
+               printxval(whence, _whence, "SEEK_???");
+       }
+       return RVAL_UDECIMAL;
+}
+#else /* !LINUX_MIPSN32 */
 int
-sys_lseek(tcp)
-struct tcb *tcp;
+sys_lseek(struct tcb *tcp)
 {
        off_t offset;
        int _whence;
 
        if (entering(tcp)) {
-               tprintf("%ld, ", tcp->u_arg[0]);
-#ifndef FREEBSD
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
                offset = tcp->u_arg[1];
                _whence = tcp->u_arg[2];
                if (_whence == SEEK_SET)
                        tprintf("%lu, ", offset);
                else
-                       tprintf("%ld, ", offset);               
-#else /* FREEBSD */
-               offset = ((off_t) tcp->u_arg[1] << 32) +  tcp->u_arg[2];
-               _whence = tcp->u_arg[4];
-               if (_whence == SEEK_SET)
-                       tprintf("%llu, ", offset);
-               else
-                       tprintf("%lld, ", offset);              
-#endif         
+                       tprintf("%ld, ", offset);
                printxval(whence, _whence, "SEEK_???");
-       } 
-#ifdef FREEBSD
-       else
-               if (!syserror(tcp))
-                       return RVAL_LUDECIMAL;
-#endif /* FREEBSD */
+       }
        return RVAL_UDECIMAL;
 }
+#endif /* LINUX_MIPSN32 */
+#endif
 
-#ifdef linux
+#ifdef LINUX
 int
-sys_llseek (tcp)
-struct tcb *tcp;
+sys_llseek(struct tcb *tcp)
 {
-    if (entering(tcp)) {
-       if (tcp->u_arg[4] == SEEK_SET)
-           tprintf("%ld, %llu, ", tcp->u_arg[0],
-                   (((long long int) tcp->u_arg[1]) << 32
-                    | (unsigned long long) tcp->u_arg[2]));
-       else
-           tprintf("%ld, %lld, ", tcp->u_arg[0],
-                   (((long long int) tcp->u_arg[1]) << 32
-                    | (unsigned long long) tcp->u_arg[2]));
-    }
-    else {
-       long long int off;
-       if (syserror(tcp) || umove(tcp, tcp->u_arg[3], &off) < 0)
-           tprintf("%#lx, ", tcp->u_arg[3]);
-       else
-           tprintf("[%llu], ", off);
-       printxval(whence, tcp->u_arg[4], "SEEK_???");
-    }
-    return 0;
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               /*
+                * This one call takes explicitly two 32-bit arguments hi, lo,
+                * rather than one 64-bit argument for which LONG_LONG works
+                * appropriate for the native byte order.
+                */
+               if (tcp->u_arg[4] == SEEK_SET)
+                       tprintf(", %llu, ",
+                               ((long long int) tcp->u_arg[1]) << 32 |
+                               (unsigned long long) (unsigned) tcp->u_arg[2]);
+               else
+                       tprintf(", %lld, ",
+                               ((long long int) tcp->u_arg[1]) << 32 |
+                               (unsigned long long) (unsigned) tcp->u_arg[2]);
+       }
+       else {
+               long long int off;
+               if (syserror(tcp) || umove(tcp, tcp->u_arg[3], &off) < 0)
+                       tprintf("%#lx, ", tcp->u_arg[3]);
+               else
+                       tprintf("[%llu], ", off);
+               printxval(whence, tcp->u_arg[4], "SEEK_???");
+       }
+       return 0;
+}
+
+int
+sys_readahead(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               int argn;
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               argn = printllval(tcp, "%lld", 1);
+               tprintf(", %ld", tcp->u_arg[argn]);
+       }
+       return 0;
 }
 #endif
 
-#if _LFS_LARGEFILE
+#if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
 int
-sys_lseek64 (tcp)
-struct tcb *tcp;
+sys_lseek64(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               long long offset = get64(tcp->u_arg [1], tcp->u_arg[2]);
+               int argn;
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
                if (tcp->u_arg[3] == SEEK_SET)
-                       tprintf("%ld, %llu, ", tcp->u_arg[0], offset);
+                       argn = printllval(tcp, "%llu, ", 1);
                else
-                       tprintf("%ld, %lld, ", tcp->u_arg[0], offset);
-               printxval(whence, tcp->u_arg[3], "SEEK_???");
+                       argn = printllval(tcp, "%lld, ", 1);
+               printxval(whence, tcp->u_arg[argn], "SEEK_???");
        }
        return RVAL_LUDECIMAL;
 }
 #endif
 
+#ifndef HAVE_LONG_LONG_OFF_T
 int
-sys_truncate(tcp)
-struct tcb *tcp;
+sys_truncate(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-#ifndef FREEBSD
                tprintf(", %lu", tcp->u_arg[1]);
-#else
-               tprintf(", %llu", ((off_t) tcp->u_arg[1] << 32) + tcp->u_arg[2]);
-#endif         
        }
        return 0;
 }
+#endif
 
+#if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
 int
-sys_ftruncate(tcp)
-struct tcb *tcp;
+sys_truncate64(struct tcb *tcp)
 {
        if (entering(tcp)) {
-#ifndef FREEBSD
-               tprintf("%ld, %lu", tcp->u_arg[0], tcp->u_arg[1]);
-#else
-               tprintf("%ld, %llu", tcp->u_arg[0],
-                       ((off_t) tcp->u_arg[1] << 32) + tcp->u_arg[2]);
-#endif         
+               printpath(tcp, tcp->u_arg[0]);
+               printllval(tcp, ", %llu", 1);
+       }
+       return 0;
+}
+#endif
+
+#ifndef HAVE_LONG_LONG_OFF_T
+int
+sys_ftruncate(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprintf(", %lu", tcp->u_arg[1]);
+       }
+       return 0;
+}
+#endif
+
+#if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
+int
+sys_ftruncate64(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printllval(tcp, "%llu", 1);
        }
        return 0;
 }
+#endif
 
 /* several stats */
 
-static struct xlat modetypes[] = {
+static const struct xlat modetypes[] = {
        { S_IFREG,      "S_IFREG"       },
        { S_IFSOCK,     "S_IFSOCK"      },
        { S_IFIFO,      "S_IFIFO"       },
@@ -471,12 +693,11 @@ static struct xlat modetypes[] = {
        { 0,            NULL            },
 };
 
-static char *
-sprintmode(mode)
-int mode;
+static const char *
+sprintmode(int mode)
 {
        static char buf[64];
-       char *s;
+       const char *s;
 
        if ((mode & S_IFMT) == 0)
                s = "";
@@ -496,67 +717,60 @@ int mode;
 }
 
 static char *
-sprinttime(t)
-time_t t;
+sprinttime(time_t t)
 {
        struct tm *tmp;
        static char buf[32];
 
        if (t == 0) {
-               sprintf(buf, "0");
+               strcpy(buf, "0");
                return buf;
        }
        tmp = localtime(&t);
-       sprintf(buf, "%02d/%02d/%02d-%02d:%02d:%02d",
-               tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
-               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+       if (tmp)
+               snprintf(buf, sizeof buf, "%02d/%02d/%02d-%02d:%02d:%02d",
+                       tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+                       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+       else
+               snprintf(buf, sizeof buf, "%lu", (unsigned long) t);
+
        return buf;
 }
 
 #ifdef LINUXSPARC
 typedef struct {
-        int     tv_sec;
-        int     tv_nsec;
+       int     tv_sec;
+       int     tv_nsec;
 } timestruct_t;
 
 struct solstat {
-        unsigned        st_dev;
-        int             st_pad1[3];     /* network id */
-        unsigned        st_ino;
-        unsigned        st_mode;
-        unsigned        st_nlink;
-        unsigned        st_uid;
-        unsigned        st_gid;
-        unsigned        st_rdev;
-        int             st_pad2[2];
-        int             st_size;
-        int             st_pad3;        /* st_size, off_t expansion */
-        timestruct_t    st_atime;
-        timestruct_t    st_mtime;
-        timestruct_t    st_ctime;
-        int             st_blksize;
-        int             st_blocks;
-        char            st_fstype[16];
-        int             st_pad4[8];     /* expansion area */
+       unsigned        st_dev;
+       int             st_pad1[3];     /* network id */
+       unsigned        st_ino;
+       unsigned        st_mode;
+       unsigned        st_nlink;
+       unsigned        st_uid;
+       unsigned        st_gid;
+       unsigned        st_rdev;
+       int             st_pad2[2];
+       int             st_size;
+       int             st_pad3;        /* st_size, off_t expansion */
+       timestruct_t    st_atime;
+       timestruct_t    st_mtime;
+       timestruct_t    st_ctime;
+       int             st_blksize;
+       int             st_blocks;
+       char            st_fstype[16];
+       int             st_pad4[8];     /* expansion area */
 };
 
 static void
-printstatsol(tcp, addr)
-struct tcb *tcp;
-long addr;
+printstatsol(struct tcb *tcp, long addr)
 {
        struct solstat statbuf;
 
-       if (!addr) {
-               tprintf("NULL");
-               return;
-       }
-       if (syserror(tcp) || !verbose(tcp)) {
-               tprintf("%#lx", addr);
-               return;
-       }
        if (umove(tcp, addr, &statbuf) < 0) {
-               tprintf("{...}");
+               tprints("{...}");
                return;
        }
        if (!abbrev(tcp)) {
@@ -584,18 +798,132 @@ long addr;
                tprintf("st_size=%u, ", statbuf.st_size);
                break;
        }
+       if (!abbrev(tcp)) {
+               tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime.tv_sec));
+               tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime.tv_sec));
+               tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime.tv_sec));
+       }
+       else
+               tprints("...}");
+}
+
+#if defined (SPARC64)
+static void
+printstat_sparc64(struct tcb *tcp, long addr)
+{
+       struct stat_sparc64 statbuf;
+
+       if (umove(tcp, addr, &statbuf) < 0) {
+               tprints("{...}");
+               return;
+       }
+
+       if (!abbrev(tcp)) {
+               tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
+                       (unsigned long) major(statbuf.st_dev),
+                       (unsigned long) minor(statbuf.st_dev),
+                       (unsigned long) statbuf.st_ino,
+                       sprintmode(statbuf.st_mode));
+               tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
+                       (unsigned long) statbuf.st_nlink,
+                       (unsigned long) statbuf.st_uid,
+                       (unsigned long) statbuf.st_gid);
+               tprintf("st_blksize=%lu, ",
+                       (unsigned long) statbuf.st_blksize);
+               tprintf("st_blocks=%lu, ",
+                       (unsigned long) statbuf.st_blocks);
+       }
+       else
+               tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
+       switch (statbuf.st_mode & S_IFMT) {
+       case S_IFCHR: case S_IFBLK:
+               tprintf("st_rdev=makedev(%lu, %lu), ",
+                       (unsigned long) major(statbuf.st_rdev),
+                       (unsigned long) minor(statbuf.st_rdev));
+               break;
+       default:
+               tprintf("st_size=%lu, ", statbuf.st_size);
+               break;
+       }
        if (!abbrev(tcp)) {
                tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
                tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
-               tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime));
+               tprintf("st_ctime=%s", sprinttime(statbuf.st_ctime));
+               tprints("}");
        }
        else
-               tprintf("...}");
+               tprints("...}");
 }
+#endif /* SPARC64 */
 #endif /* LINUXSPARC */
 
+#if defined LINUX && defined POWERPC64
+struct stat_powerpc32 {
+       unsigned int    st_dev;
+       unsigned int    st_ino;
+       unsigned int    st_mode;
+       unsigned short  st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_rdev;
+       unsigned int    st_size;
+       unsigned int    st_blksize;
+       unsigned int    st_blocks;
+       unsigned int    st_atime;
+       unsigned int    st_atime_nsec;
+       unsigned int    st_mtime;
+       unsigned int    st_mtime_nsec;
+       unsigned int    st_ctime;
+       unsigned int    st_ctime_nsec;
+       unsigned int    __unused4;
+       unsigned int    __unused5;
+};
+
+static void
+printstat_powerpc32(struct tcb *tcp, long addr)
+{
+       struct stat_powerpc32 statbuf;
+
+       if (umove(tcp, addr, &statbuf) < 0) {
+               tprints("{...}");
+               return;
+       }
+
+       if (!abbrev(tcp)) {
+               tprintf("{st_dev=makedev(%u, %u), st_ino=%u, st_mode=%s, ",
+                       major(statbuf.st_dev), minor(statbuf.st_dev),
+                       statbuf.st_ino,
+                       sprintmode(statbuf.st_mode));
+               tprintf("st_nlink=%u, st_uid=%u, st_gid=%u, ",
+                       statbuf.st_nlink, statbuf.st_uid, statbuf.st_gid);
+               tprintf("st_blksize=%u, ", statbuf.st_blksize);
+               tprintf("st_blocks=%u, ", statbuf.st_blocks);
+       }
+       else
+               tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
+       switch (statbuf.st_mode & S_IFMT) {
+       case S_IFCHR: case S_IFBLK:
+               tprintf("st_rdev=makedev(%lu, %lu), ",
+                       (unsigned long) major(statbuf.st_rdev),
+                       (unsigned long) minor(statbuf.st_rdev));
+               break;
+       default:
+               tprintf("st_size=%u, ", statbuf.st_size);
+               break;
+       }
+       if (!abbrev(tcp)) {
+               tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
+               tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
+               tprintf("st_ctime=%s", sprinttime(statbuf.st_ctime));
+               tprints("}");
+       }
+       else
+               tprints("...}");
+}
+#endif /* LINUX && POWERPC64 */
+
+static const struct xlat fileflags[] = {
 #ifdef FREEBSD
-static struct xlat fileflags[] = {
        { UF_NODUMP,    "UF_NODUMP"     },
        { UF_IMMUTABLE, "UF_IMMUTABLE"  },
        { UF_APPEND,    "UF_APPEND"     },
@@ -605,154 +933,223 @@ static struct xlat fileflags[] = {
        { SF_IMMUTABLE, "SF_IMMUTABLE"  },
        { SF_APPEND,    "SF_APPEND"     },
        { SF_NOUNLINK,  "SF_NOUNLINK"   },
+#elif UNIXWARE >= 2
+#ifdef _S_ISMLD
+       { _S_ISMLD,     "_S_ISMLD"      },
+#endif
+#ifdef _S_ISMOUNTED
+       { _S_ISMOUNTED, "_S_ISMOUNTED"  },
+#endif
+#endif
        { 0,            NULL            },
 };
 
+#ifdef FREEBSD
 int
-sys_chflags(tcp)
-struct tcb *tcp;
+sys_chflags(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-               if (tcp->u_arg[1])
-                       printflags(fileflags, tcp->u_arg[1]);
-               else
-                       tprintf("0");
+               tprints(", ");
+               printflags(fileflags, tcp->u_arg[1], "UF_???");
        }
        return 0;
 }
 
 int
-sys_fchflags(tcp)
-struct tcb *tcp;
+sys_fchflags(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%ld, ", tcp->u_arg[0]);
-               if (tcp->u_arg[1])
-                       printflags(fileflags, tcp->u_arg[1]);
-               else
-                       tprintf("0");
+               printflags(fileflags, tcp->u_arg[1], "UF_???");
        }
        return 0;
 }
 #endif
 
+#ifndef HAVE_LONG_LONG_OFF_T
 static void
-realprintstat(tcp, statbuf)
-struct tcb *tcp;
-struct stat *statbuf;
-{
-    if (!abbrev(tcp)) {
-           tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
-                   (unsigned long) major(statbuf->st_dev),
-                   (unsigned long) minor(statbuf->st_dev),
-                   (unsigned long) statbuf->st_ino,
-                   sprintmode(statbuf->st_mode));
-           tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
-                   (unsigned long) statbuf->st_nlink,
-                   (unsigned long) statbuf->st_uid,
-                   (unsigned long) statbuf->st_gid);
-#ifdef HAVE_ST_BLKSIZE
-           tprintf("st_blksize=%lu, ", (unsigned long) statbuf->st_blksize);
-#endif /* HAVE_ST_BLKSIZE */
-#ifdef HAVE_ST_BLOCKS
-           tprintf("st_blocks=%lu, ", (unsigned long) statbuf->st_blocks);
-#endif /* HAVE_ST_BLOCKS */
-    }
-    else
-           tprintf("{st_mode=%s, ", sprintmode(statbuf->st_mode));
-    switch (statbuf->st_mode & S_IFMT) {
-    case S_IFCHR: case S_IFBLK:
-#ifdef HAVE_ST_RDEV
-           tprintf("st_rdev=makedev(%lu, %lu), ",
-                   (unsigned long) major(statbuf->st_rdev),
-                   (unsigned long) minor(statbuf->st_rdev));
-#else /* !HAVE_ST_RDEV */
-           tprintf("st_size=makedev(%lu, %lu), ",
-                   (unsigned long) major(statbuf->st_size),
-                   (unsigned long) minor(statbuf->st_size));
-#endif /* !HAVE_ST_RDEV */
-           break;
-    default:
-           tprintf("st_size=%lu, ", statbuf->st_size);
-           break;
-    }
-    if (!abbrev(tcp)) {
-           tprintf("st_atime=%s, ", sprinttime(statbuf->st_atime));
-           tprintf("st_mtime=%s, ", sprinttime(statbuf->st_mtime));
-#ifndef FREEBSD
-           tprintf("st_ctime=%s}", sprinttime(statbuf->st_ctime));
-#else /* FREEBSD */
-           tprintf("st_ctime=%s, ", sprinttime(statbuf->st_ctime));
-           tprintf("st_flags=");
-           if (statbuf->st_flags) {
-                   printflags(fileflags, statbuf->st_flags);
-           } else
-                   tprintf("0");
-           tprintf(", st_gen=%u}", statbuf->st_gen);
-#endif /* FREEBSD */
-    }
-    else
-           tprintf("...}");
+realprintstat(struct tcb *tcp, struct stat *statbuf)
+{
+       if (!abbrev(tcp)) {
+               tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
+                       (unsigned long) major(statbuf->st_dev),
+                       (unsigned long) minor(statbuf->st_dev),
+                       (unsigned long) statbuf->st_ino,
+                       sprintmode(statbuf->st_mode));
+               tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
+                       (unsigned long) statbuf->st_nlink,
+                       (unsigned long) statbuf->st_uid,
+                       (unsigned long) statbuf->st_gid);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+               tprintf("st_blksize=%lu, ", (unsigned long) statbuf->st_blksize);
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+               tprintf("st_blocks=%lu, ", (unsigned long) statbuf->st_blocks);
+#endif
+       }
+       else
+               tprintf("{st_mode=%s, ", sprintmode(statbuf->st_mode));
+       switch (statbuf->st_mode & S_IFMT) {
+       case S_IFCHR: case S_IFBLK:
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+               tprintf("st_rdev=makedev(%lu, %lu), ",
+                       (unsigned long) major(statbuf->st_rdev),
+                       (unsigned long) minor(statbuf->st_rdev));
+#else /* !HAVE_STRUCT_STAT_ST_RDEV */
+               tprintf("st_size=makedev(%lu, %lu), ",
+                       (unsigned long) major(statbuf->st_size),
+                       (unsigned long) minor(statbuf->st_size));
+#endif /* !HAVE_STRUCT_STAT_ST_RDEV */
+               break;
+       default:
+               tprintf("st_size=%lu, ", (unsigned long) statbuf->st_size);
+               break;
+       }
+       if (!abbrev(tcp)) {
+               tprintf("st_atime=%s, ", sprinttime(statbuf->st_atime));
+               tprintf("st_mtime=%s, ", sprinttime(statbuf->st_mtime));
+               tprintf("st_ctime=%s", sprinttime(statbuf->st_ctime));
+#if HAVE_STRUCT_STAT_ST_FLAGS
+               tprints(", st_flags=");
+               printflags(fileflags, statbuf->st_flags, "UF_???");
+#endif
+#if HAVE_STRUCT_STAT_ST_ACLCNT
+               tprintf(", st_aclcnt=%d", statbuf->st_aclcnt);
+#endif
+#if HAVE_STRUCT_STAT_ST_LEVEL
+               tprintf(", st_level=%ld", statbuf->st_level);
+#endif
+#if HAVE_STRUCT_STAT_ST_FSTYPE
+               tprintf(", st_fstype=%.*s",
+                       (int) sizeof statbuf->st_fstype, statbuf->st_fstype);
+#endif
+#if HAVE_STRUCT_STAT_ST_GEN
+               tprintf(", st_gen=%u", statbuf->st_gen);
+#endif
+               tprints("}");
+       }
+       else
+               tprints("...}");
 }
 
 
 static void
-printstat(tcp, addr)
-struct tcb *tcp;
-long addr;
+printstat(struct tcb *tcp, long addr)
 {
        struct stat statbuf;
 
-#ifdef LINUXSPARC
-       if (current_personality == 1) {
-               printstatsol(tcp, addr);
-               return;
-       }
-#endif /* LINUXSPARC */
-
        if (!addr) {
-               tprintf("NULL");
+               tprints("NULL");
                return;
        }
        if (syserror(tcp) || !verbose(tcp)) {
                tprintf("%#lx", addr);
                return;
        }
-       if (umove(tcp, addr, &statbuf) < 0) {
-               tprintf("{...}");
+
+#ifdef LINUXSPARC
+       if (current_personality == 1) {
+               printstatsol(tcp, addr);
                return;
        }
-
-       realprintstat(tcp, &statbuf);
+#ifdef SPARC64
+       else if (current_personality == 2) {
+               printstat_sparc64(tcp, addr);
+               return;
+       }
+#endif
+#endif /* LINUXSPARC */
+
+#if defined LINUX && defined POWERPC64
+       if (current_personality == 1) {
+               printstat_powerpc32(tcp, addr);
+               return;
+       }
+#endif
+
+       if (umove(tcp, addr, &statbuf) < 0) {
+               tprints("{...}");
+               return;
+       }
+
+       realprintstat(tcp, &statbuf);
 }
+#endif /* !HAVE_LONG_LONG_OFF_T */
+
+#if !defined HAVE_STAT64 && defined LINUX && defined X86_64
+/*
+ * Linux x86_64 has unified `struct stat' but its i386 biarch needs
+ * `struct stat64'.  Its <asm-i386/stat.h> definition expects 32-bit `long'.
+ * <linux/include/asm-x86_64/ia32.h> is not in the public includes set.
+ * __GNUC__ is needed for the required __attribute__ below.
+ */
+struct stat64 {
+       unsigned long long      st_dev;
+       unsigned char   __pad0[4];
+       unsigned int    __st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned long long      st_rdev;
+       unsigned char   __pad3[4];
+       long long       st_size;
+       unsigned int    st_blksize;
+       unsigned long long      st_blocks;
+       unsigned int    st_atime;
+       unsigned int    st_atime_nsec;
+       unsigned int    st_mtime;
+       unsigned int    st_mtime_nsec;
+       unsigned int    st_ctime;
+       unsigned int    st_ctime_nsec;
+       unsigned long long      st_ino;
+} __attribute__((packed));
+# define HAVE_STAT64   1
+# define STAT64_SIZE   96
+#endif
 
 #ifdef HAVE_STAT64
 static void
-printstat64(tcp, addr)
-struct tcb *tcp;
-long addr;
+printstat64(struct tcb *tcp, long addr)
 {
        struct stat64 statbuf;
 
-#ifdef LINUXSPARC
-       if (current_personality == 1) {
-               printstatsol(tcp, addr);
-               return;
-       }
-#endif /* LINUXSPARC */
+#ifdef STAT64_SIZE
+       (void) sizeof(char[sizeof statbuf == STAT64_SIZE ? 1 : -1]);
+#endif
 
        if (!addr) {
-               tprintf("NULL");
+               tprints("NULL");
                return;
        }
        if (syserror(tcp) || !verbose(tcp)) {
                tprintf("%#lx", addr);
                return;
        }
+
+#ifdef LINUXSPARC
+       if (current_personality == 1) {
+               printstatsol(tcp, addr);
+               return;
+       }
+# ifdef SPARC64
+       else if (current_personality == 2) {
+               printstat_sparc64(tcp, addr);
+               return;
+       }
+# endif
+#endif /* LINUXSPARC */
+
+#if defined LINUX && defined X86_64
+       if (current_personality == 0) {
+               printstat(tcp, addr);
+               return;
+       }
+#endif
+
        if (umove(tcp, addr, &statbuf) < 0) {
-               tprintf("{...}");
+               tprints("{...}");
                return;
        }
 
@@ -774,120 +1171,138 @@ long addr;
                        (unsigned long) statbuf.st_nlink,
                        (unsigned long) statbuf.st_uid,
                        (unsigned long) statbuf.st_gid);
-#ifdef HAVE_ST_BLKSIZE
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
                tprintf("st_blksize=%lu, ",
                        (unsigned long) statbuf.st_blksize);
-#endif /* HAVE_ST_BLKSIZE */
-#ifdef HAVE_ST_BLOCKS
+#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
                tprintf("st_blocks=%lu, ", (unsigned long) statbuf.st_blocks);
-#endif /* HAVE_ST_BLOCKS */
+#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
        }
        else
                tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
        switch (statbuf.st_mode & S_IFMT) {
        case S_IFCHR: case S_IFBLK:
-#ifdef HAVE_ST_RDEV
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
                tprintf("st_rdev=makedev(%lu, %lu), ",
                        (unsigned long) major(statbuf.st_rdev),
                        (unsigned long) minor(statbuf.st_rdev));
-#else /* !HAVE_ST_RDEV */
+#else /* !HAVE_STRUCT_STAT_ST_RDEV */
                tprintf("st_size=makedev(%lu, %lu), ",
                        (unsigned long) major(statbuf.st_size),
                        (unsigned long) minor(statbuf.st_size));
-#endif /* !HAVE_ST_RDEV */
+#endif /* !HAVE_STRUCT_STAT_ST_RDEV */
                break;
        default:
-               tprintf("st_size=%llu, ", statbuf.st_size);
+#ifdef HAVE_LONG_LONG
+               tprintf("st_size=%llu, ", (unsigned long long) statbuf.st_size);
+#else
+               tprintf("st_size=%lu, ", (unsigned long) statbuf.st_size);
+#endif
                break;
        }
        if (!abbrev(tcp)) {
                tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
                tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
-               tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime));
+               tprintf("st_ctime=%s", sprinttime(statbuf.st_ctime));
+#if HAVE_STRUCT_STAT_ST_FLAGS
+               tprints(", st_flags=");
+               printflags(fileflags, statbuf.st_flags, "UF_???");
+#endif
+#if HAVE_STRUCT_STAT_ST_ACLCNT
+               tprintf(", st_aclcnt=%d", statbuf.st_aclcnt);
+#endif
+#if HAVE_STRUCT_STAT_ST_LEVEL
+               tprintf(", st_level=%ld", statbuf.st_level);
+#endif
+#if HAVE_STRUCT_STAT_ST_FSTYPE
+               tprintf(", st_fstype=%.*s",
+                       (int) sizeof statbuf.st_fstype, statbuf.st_fstype);
+#endif
+#if HAVE_STRUCT_STAT_ST_GEN
+               tprintf(", st_gen=%u", statbuf.st_gen);
+#endif
+               tprints("}");
        }
        else
-               tprintf("...}");
+               tprints("...}");
 }
 #endif /* HAVE_STAT64 */
 
-#if defined(linux) && !defined(IA64)
+#if defined(LINUX) && defined(HAVE_STRUCT___OLD_KERNEL_STAT) \
+    && !defined(HAVE_LONG_LONG_OFF_T)
 static void
-convertoldstat(oldbuf, newbuf)
-const struct __old_kernel_stat *oldbuf;
-struct stat *newbuf;
-{
-    newbuf->st_dev=oldbuf->st_dev;
-    newbuf->st_ino=oldbuf->st_ino;
-    newbuf->st_mode=oldbuf->st_mode;
-    newbuf->st_nlink=oldbuf->st_nlink;
-    newbuf->st_uid=oldbuf->st_uid;
-    newbuf->st_gid=oldbuf->st_gid;
-    newbuf->st_rdev=oldbuf->st_rdev;
-    newbuf->st_size=oldbuf->st_size;
-    newbuf->st_atime=oldbuf->st_atime;
-    newbuf->st_mtime=oldbuf->st_mtime;
-    newbuf->st_ctime=oldbuf->st_ctime;
-    newbuf->st_blksize=0;      /* not supported in old_stat */
-    newbuf->st_blocks=0;               /* not supported in old_stat */
+convertoldstat(const struct __old_kernel_stat *oldbuf, struct stat *newbuf)
+{
+       newbuf->st_dev = oldbuf->st_dev;
+       newbuf->st_ino = oldbuf->st_ino;
+       newbuf->st_mode = oldbuf->st_mode;
+       newbuf->st_nlink = oldbuf->st_nlink;
+       newbuf->st_uid = oldbuf->st_uid;
+       newbuf->st_gid = oldbuf->st_gid;
+       newbuf->st_rdev = oldbuf->st_rdev;
+       newbuf->st_size = oldbuf->st_size;
+       newbuf->st_atime = oldbuf->st_atime;
+       newbuf->st_mtime = oldbuf->st_mtime;
+       newbuf->st_ctime = oldbuf->st_ctime;
+       newbuf->st_blksize = 0; /* not supported in old_stat */
+       newbuf->st_blocks = 0; /* not supported in old_stat */
 }
 
 
 static void
-printoldstat(tcp, addr)
-struct tcb *tcp;
-long addr;
+printoldstat(struct tcb *tcp, long addr)
 {
        struct __old_kernel_stat statbuf;
        struct stat newstatbuf;
 
-#ifdef LINUXSPARC
-       if (current_personality == 1) {
-               printstatsol(tcp, addr);
-               return;
-       }
-#endif /* LINUXSPARC */
-
        if (!addr) {
-               tprintf("NULL");
+               tprints("NULL");
                return;
        }
        if (syserror(tcp) || !verbose(tcp)) {
                tprintf("%#lx", addr);
                return;
        }
+
+#ifdef LINUXSPARC
+       if (current_personality == 1) {
+               printstatsol(tcp, addr);
+               return;
+       }
+#endif /* LINUXSPARC */
+
        if (umove(tcp, addr, &statbuf) < 0) {
-               tprintf("{...}");
+               tprints("{...}");
                return;
        }
 
        convertoldstat(&statbuf, &newstatbuf);
        realprintstat(tcp, &newstatbuf);
 }
-#endif /* linux && !IA64 */
-
+#endif /* LINUX && !IA64 && !HPPA && !X86_64 && !S390 && !S390X */
 
+#ifndef HAVE_LONG_LONG_OFF_T
 int
-sys_stat(tcp)
-struct tcb *tcp;
+sys_stat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
+#endif
 
-#ifdef linux
 int
-sys_stat64(tcp)
-struct tcb *tcp;
+sys_stat64(struct tcb *tcp)
 {
 #ifdef HAVE_STAT64
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstat64(tcp, tcp->u_arg[1]);
        }
@@ -897,43 +1312,78 @@ struct tcb *tcp;
 #endif
 }
 
-# if !defined(IA64)
+#ifdef LINUX
+static const struct xlat fstatatflags[] = {
+#ifndef AT_SYMLINK_NOFOLLOW
+# define AT_SYMLINK_NOFOLLOW     0x100
+#endif
+       { AT_SYMLINK_NOFOLLOW,  "AT_SYMLINK_NOFOLLOW"   },
+       { 0,                    NULL                    },
+};
+#define utimensatflags fstatatflags
+
+int
+sys_newfstatat(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               print_dirfd(tcp, tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+       } else {
+#ifdef POWERPC64
+               if (current_personality == 0)
+                       printstat(tcp, tcp->u_arg[2]);
+               else
+                       printstat64(tcp, tcp->u_arg[2]);
+#elif defined HAVE_STAT64
+               printstat64(tcp, tcp->u_arg[2]);
+#else
+               printstat(tcp, tcp->u_arg[2]);
+#endif
+               tprints(", ");
+               printflags(fstatatflags, tcp->u_arg[3], "AT_???");
+       }
+       return 0;
+}
+#endif
+
+#if defined(LINUX) && defined(HAVE_STRUCT___OLD_KERNEL_STAT) \
+    && !defined(HAVE_LONG_LONG_OFF_T)
 int
-sys_oldstat(tcp)
-struct tcb *tcp;
+sys_oldstat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printoldstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
-# endif /* !IA64 */
-#endif /* linux */
+#endif /* LINUX && HAVE_STRUCT___OLD_KERNEL_STAT */
 
+#ifndef HAVE_LONG_LONG_OFF_T
 int
-sys_fstat(tcp)
-struct tcb *tcp;
+sys_fstat(struct tcb *tcp)
 {
-       if (entering(tcp))
-               tprintf("%ld, ", tcp->u_arg[0]);
-       else {
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+       } else {
                printstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
+#endif
 
-#ifdef linux
 int
-sys_fstat64(tcp)
-struct tcb *tcp;
+sys_fstat64(struct tcb *tcp)
 {
 #ifdef HAVE_STAT64
-       if (entering(tcp))
-               tprintf("%ld, ", tcp->u_arg[0]);
-       else {
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+       } else {
                printstat64(tcp, tcp->u_arg[1]);
        }
        return 0;
@@ -942,43 +1392,42 @@ struct tcb *tcp;
 #endif
 }
 
-# if !defined(IA64)
+#if defined(LINUX) && defined(HAVE_STRUCT___OLD_KERNEL_STAT) \
+    && !defined(HAVE_LONG_LONG_OFF_T)
 int
-sys_oldfstat(tcp)
-struct tcb *tcp;
+sys_oldfstat(struct tcb *tcp)
 {
-       if (entering(tcp))
-               tprintf("%ld, ", tcp->u_arg[0]);
-       else {
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+       } else {
                printoldstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
-# endif /* !IA64 */
-#endif
+#endif /* LINUX && HAVE_STRUCT___OLD_KERNEL_STAT */
 
+#ifndef HAVE_LONG_LONG_OFF_T
 int
-sys_lstat(tcp)
-struct tcb *tcp;
+sys_lstat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
+#endif
 
-#ifdef linux
 int
-sys_lstat64(tcp)
-struct tcb *tcp;
+sys_lstat64(struct tcb *tcp)
 {
 #ifdef HAVE_STAT64
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstat64(tcp, tcp->u_arg[1]);
        }
@@ -988,33 +1437,31 @@ struct tcb *tcp;
 #endif
 }
 
-# if !defined(IA64)
+#if defined(LINUX) && defined(HAVE_STRUCT___OLD_KERNEL_STAT) \
+    && !defined(HAVE_LONG_LONG_OFF_T)
 int
-sys_oldlstat(tcp)
-struct tcb *tcp;
+sys_oldlstat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printoldstat(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
-# endif /* !IA64 */
-#endif
+#endif /* LINUX && HAVE_STRUCT___OLD_KERNEL_STAT */
 
 
 #if defined(SVR4) || defined(LINUXSPARC)
 
 int
-sys_xstat(tcp)
-struct tcb *tcp;
+sys_xstat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%ld, ", tcp->u_arg[0]);
                printpath(tcp, tcp->u_arg[1]);
-               tprintf(", ");
+               tprints(", ");
        } else {
 #ifdef _STAT64_VER
                if (tcp->u_arg[0] == _STAT64_VER)
@@ -1027,8 +1474,7 @@ struct tcb *tcp;
 }
 
 int
-sys_fxstat(tcp)
-struct tcb *tcp;
+sys_fxstat(struct tcb *tcp)
 {
        if (entering(tcp))
                tprintf("%ld, %ld, ", tcp->u_arg[0], tcp->u_arg[1]);
@@ -1044,13 +1490,12 @@ struct tcb *tcp;
 }
 
 int
-sys_lxstat(tcp)
-struct tcb *tcp;
+sys_lxstat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%ld, ", tcp->u_arg[0]);
                printpath(tcp, tcp->u_arg[1]);
-               tprintf(", ");
+               tprints(", ");
        } else {
 #ifdef _STAT64_VER
                if (tcp->u_arg[0] == _STAT64_VER)
@@ -1063,8 +1508,7 @@ struct tcb *tcp;
 }
 
 int
-sys_xmknod(tcp)
-struct tcb *tcp;
+sys_xmknod(struct tcb *tcp)
 {
        int mode = tcp->u_arg[2];
 
@@ -1078,11 +1522,11 @@ struct tcb *tcp;
                        tprintf(", makedev(%lu, %lu)",
                                (unsigned long) ((tcp->u_arg[3] >> 18) & 0x3fff),
                                (unsigned long) (tcp->u_arg[3] & 0x3ffff));
-#else          
+#else
                        tprintf(", makedev(%lu, %lu)",
                                (unsigned long) major(tcp->u_arg[3]),
                                (unsigned long) minor(tcp->u_arg[3]));
-#endif                         
+#endif
                        break;
                default:
                        break;
@@ -1095,7 +1539,7 @@ struct tcb *tcp;
 
 #include <sys/acl.h>
 
-struct xlat aclcmds[] = {
+static const struct xlat aclcmds[] = {
 #ifdef SETACL
        { SETACL,       "SETACL"        },
 #endif
@@ -1107,23 +1551,22 @@ struct xlat aclcmds[] = {
 #endif
 #ifdef ACL_GET
        { ACL_GET,      "ACL_GET"       },
-#endif 
+#endif
 #ifdef ACL_SET
        { ACL_SET,      "ACL_SET"       },
-#endif 
+#endif
 #ifdef ACL_CNT
        { ACL_CNT,      "ACL_CNT"       },
-#endif 
+#endif
        { 0,            NULL            },
 };
 
 int
-sys_acl(tcp)
-struct tcb *tcp;
+sys_acl(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
                printxval(aclcmds, tcp->u_arg[1], "???ACL???");
                tprintf(", %ld", tcp->u_arg[2]);
                /*
@@ -1133,15 +1576,14 @@ struct tcb *tcp;
                if (tcp->u_arg[3])
                        tprintf(", %#lx", tcp->u_arg[3]);
                else
-                       tprintf(", NULL");
+                       tprints(", NULL");
        }
        return 0;
 }
 
 
 int
-sys_facl(tcp)
-struct tcb *tcp;
+sys_facl(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%ld, ", tcp->u_arg[0]);
@@ -1154,29 +1596,28 @@ struct tcb *tcp;
                if (tcp->u_arg[3])
                        tprintf(", %#lx", tcp->u_arg[3]);
                else
-                       tprintf(", NULL");
+                       tprints(", NULL");
        }
        return 0;
 }
 
 
-struct xlat aclipc[] = {
+static const struct xlat aclipc[] = {
 #ifdef IPC_SHM
        { IPC_SHM,      "IPC_SHM"       },
-#endif 
+#endif
 #ifdef IPC_SEM
        { IPC_SEM,      "IPC_SEM"       },
-#endif 
+#endif
 #ifdef IPC_MSG
        { IPC_MSG,      "IPC_MSG"       },
-#endif 
+#endif
        { 0,            NULL            },
 };
 
 
 int
-sys_aclipc(tcp)
-struct tcb *tcp;
+sys_aclipc(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printxval(aclipc, tcp->u_arg[0], "???IPC???");
@@ -1190,20 +1631,18 @@ struct tcb *tcp;
                if (tcp->u_arg[4])
                        tprintf(", %#lx", tcp->u_arg[4]);
                else
-                       tprintf(", NULL");
+                       tprints(", NULL");
        }
        return 0;
 }
 
-
-
 #endif /* HAVE_SYS_ACL_H */
 
 #endif /* SVR4 || LINUXSPARC */
 
-#ifdef linux
+#ifdef LINUX
 
-static struct xlat fsmagic[] = {
+static const struct xlat fsmagic[] = {
        { 0x73757245,   "CODA_SUPER_MAGIC"      },
        { 0x012ff7b7,   "COH_SUPER_MAGIC"       },
        { 0x1373,       "DEVFS_SUPER_MAGIC"     },
@@ -1232,35 +1671,33 @@ static struct xlat fsmagic[] = {
        { 0x54190100,   "UFS_CIGAM"             },
        { 0x012ff7b4,   "XENIX_SUPER_MAGIC"     },
        { 0x012fd16d,   "XIAFS_SUPER_MAGIC"     },
+       { 0x62656572,   "SYSFS_MAGIC"           },
        { 0,            NULL                    },
 };
 
-#endif /* linux */
+#endif /* LINUX */
 
 #ifndef SVR4
 
-static char *
-sprintfstype(magic)
-int magic;
+static const char *
+sprintfstype(int magic)
 {
        static char buf[32];
-#ifdef linux
-       char *s;
+#ifdef LINUX
+       const char *s;
 
        s = xlookup(fsmagic, magic);
        if (s) {
                sprintf(buf, "\"%s\"", s);
                return buf;
        }
-#endif /* linux */
+#endif /* LINUX */
        sprintf(buf, "%#x", magic);
        return buf;
 }
 
 static void
-printstatfs(tcp, addr)
-struct tcb *tcp;
-long addr;
+printstatfs(struct tcb *tcp, long addr)
 {
        struct statfs statbuf;
 
@@ -1269,7 +1706,7 @@ long addr;
                return;
        }
        if (umove(tcp, addr, &statbuf) < 0) {
-               tprintf("{...}");
+               tprints("{...}");
                return;
        }
 #ifdef ALPHA
@@ -1277,31 +1714,37 @@ long addr;
        tprintf("{f_type=%s, f_fbsize=%u, f_blocks=%u, f_bfree=%u, ",
                sprintfstype(statbuf.f_type),
                statbuf.f_bsize, statbuf.f_blocks, statbuf.f_bfree);
-       tprintf("f_bavail=%u, f_files=%u, f_ffree=%u, f_namelen=%u",
-               statbuf.f_bavail,statbuf.f_files, statbuf.f_ffree, statbuf.f_namelen);
+       tprintf("f_bavail=%u, f_files=%u, f_ffree=%u, f_fsid={%d, %d}, f_namelen=%u",
+               statbuf.f_bavail, statbuf.f_files, statbuf.f_ffree,
+               statbuf.f_fsid.__val[0], statbuf.f_fsid.__val[1],
+               statbuf.f_namelen);
 #else /* !ALPHA */
        tprintf("{f_type=%s, f_bsize=%lu, f_blocks=%lu, f_bfree=%lu, ",
                sprintfstype(statbuf.f_type),
                (unsigned long)statbuf.f_bsize,
                (unsigned long)statbuf.f_blocks,
                (unsigned long)statbuf.f_bfree);
-       tprintf("f_files=%lu, f_ffree=%lu",
+       tprintf("f_bavail=%lu, f_files=%lu, f_ffree=%lu, f_fsid={%d, %d}",
+               (unsigned long)statbuf.f_bavail,
                (unsigned long)statbuf.f_files,
-               (unsigned long)statbuf.f_ffree);
-#ifdef linux
+               (unsigned long)statbuf.f_ffree,
+               statbuf.f_fsid.__val[0], statbuf.f_fsid.__val[1]);
+#ifdef LINUX
        tprintf(", f_namelen=%lu", (unsigned long)statbuf.f_namelen);
-#endif /* linux */
+#endif /* LINUX */
 #endif /* !ALPHA */
-       tprintf("}");
+#ifdef _STATFS_F_FRSIZE
+       tprintf(", f_frsize=%lu", (unsigned long)statbuf.f_frsize);
+#endif
+       tprints("}");
 }
 
 int
-sys_statfs(tcp)
-struct tcb *tcp;
+sys_statfs(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstatfs(tcp, tcp->u_arg[1]);
        }
@@ -1309,26 +1752,142 @@ struct tcb *tcp;
 }
 
 int
-sys_fstatfs(tcp)
-struct tcb *tcp;
+sys_fstatfs(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               tprintf("%lu, ", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
        } else {
                printstatfs(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
 
-#if defined(linux) && defined(__alpha)
+#if defined LINUX && defined HAVE_STATFS64
+static void
+printstatfs64(struct tcb *tcp, long addr)
+{
+       struct statfs64 statbuf;
+
+       if (syserror(tcp) || !verbose(tcp)) {
+               tprintf("%#lx", addr);
+               return;
+       }
+       if (umove(tcp, addr, &statbuf) < 0) {
+               tprints("{...}");
+               return;
+       }
+       tprintf("{f_type=%s, f_bsize=%llu, f_blocks=%llu, f_bfree=%llu, ",
+               sprintfstype(statbuf.f_type),
+               (unsigned long long)statbuf.f_bsize,
+               (unsigned long long)statbuf.f_blocks,
+               (unsigned long long)statbuf.f_bfree);
+       tprintf("f_bavail=%llu, f_files=%llu, f_ffree=%llu, f_fsid={%d, %d}",
+               (unsigned long long)statbuf.f_bavail,
+               (unsigned long long)statbuf.f_files,
+               (unsigned long long)statbuf.f_ffree,
+               statbuf.f_fsid.__val[0], statbuf.f_fsid.__val[1]);
+       tprintf(", f_namelen=%lu", (unsigned long)statbuf.f_namelen);
+#ifdef _STATFS_F_FRSIZE
+       tprintf(", f_frsize=%llu", (unsigned long long)statbuf.f_frsize);
+#endif
+#ifdef _STATFS_F_FLAGS
+       tprintf(", f_flags=%llu", (unsigned long long)statbuf.f_flags);
+#endif
+       tprints("}");
+}
+
+struct compat_statfs64 {
+       uint32_t f_type;
+       uint32_t f_bsize;
+       uint64_t f_blocks;
+       uint64_t f_bfree;
+       uint64_t f_bavail;
+       uint64_t f_files;
+       uint64_t f_ffree;
+       fsid_t f_fsid;
+       uint32_t f_namelen;
+       uint32_t f_frsize;
+       uint32_t f_flags;
+       uint32_t f_spare[4];
+}
+#if defined(X86_64) || defined(IA64)
+  __attribute__ ((packed, aligned(4)))
+#endif
+;
+
+static void
+printcompat_statfs64(struct tcb *tcp, long addr)
+{
+       struct compat_statfs64 statbuf;
+
+       if (syserror(tcp) || !verbose(tcp)) {
+               tprintf("%#lx", addr);
+               return;
+       }
+       if (umove(tcp, addr, &statbuf) < 0) {
+               tprints("{...}");
+               return;
+       }
+       tprintf("{f_type=%s, f_bsize=%lu, f_blocks=%llu, f_bfree=%llu, ",
+               sprintfstype(statbuf.f_type),
+               (unsigned long)statbuf.f_bsize,
+               (unsigned long long)statbuf.f_blocks,
+               (unsigned long long)statbuf.f_bfree);
+       tprintf("f_bavail=%llu, f_files=%llu, f_ffree=%llu, f_fsid={%d, %d}",
+               (unsigned long long)statbuf.f_bavail,
+               (unsigned long long)statbuf.f_files,
+               (unsigned long long)statbuf.f_ffree,
+               statbuf.f_fsid.__val[0], statbuf.f_fsid.__val[1]);
+       tprintf(", f_namelen=%lu", (unsigned long)statbuf.f_namelen);
+       tprintf(", f_frsize=%lu", (unsigned long)statbuf.f_frsize);
+       tprintf(", f_flags=%lu", (unsigned long)statbuf.f_frsize);
+       tprints("}");
+}
+
+int
+sys_statfs64(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printpath(tcp, tcp->u_arg[0]);
+               tprintf(", %lu, ", tcp->u_arg[1]);
+       } else {
+               if (tcp->u_arg[1] == sizeof(struct statfs64))
+                       printstatfs64(tcp, tcp->u_arg[2]);
+               else if (tcp->u_arg[1] == sizeof(struct compat_statfs64))
+                       printcompat_statfs64(tcp, tcp->u_arg[2]);
+               else
+                       tprints("{???}");
+       }
+       return 0;
+}
+
+int
+sys_fstatfs64(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprintf(", %lu, ", tcp->u_arg[1]);
+       } else {
+               if (tcp->u_arg[1] == sizeof(struct statfs64))
+                       printstatfs64(tcp, tcp->u_arg[2]);
+               else if (tcp->u_arg[1] == sizeof(struct compat_statfs64))
+                       printcompat_statfs64(tcp, tcp->u_arg[2]);
+               else
+                       tprints("{???}");
+       }
+       return 0;
+}
+#endif
+
+#if defined(LINUX) && defined(__alpha)
 
 int
-osf_statfs(tcp)
-struct tcb *tcp;
+osf_statfs(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
        } else {
                printstatfs(tcp, tcp->u_arg[1]);
                tprintf(", %lu", tcp->u_arg[2]);
@@ -1337,8 +1896,7 @@ struct tcb *tcp;
 }
 
 int
-osf_fstatfs(tcp)
-struct tcb *tcp;
+osf_fstatfs(struct tcb *tcp)
 {
        if (entering(tcp)) {
                tprintf("%lu, ", tcp->u_arg[0]);
@@ -1348,15 +1906,13 @@ struct tcb *tcp;
        }
        return 0;
 }
-#endif /* linux && __alpha */
+#endif /* LINUX && __alpha */
 
 #endif /* !SVR4 */
 
 #ifdef SUNOS4
-
 int
-sys_ustat(tcp)
-struct tcb *tcp;
+sys_ustat(struct tcb *tcp)
 {
        struct ustat statbuf;
 
@@ -1369,7 +1925,7 @@ struct tcb *tcp;
                if (syserror(tcp) || !verbose(tcp))
                        tprintf("%#lx", tcp->u_arg[1]);
                else if (umove(tcp, tcp->u_arg[1], &statbuf) < 0)
-                       tprintf("{...}");
+                       tprints("{...}");
                else {
                        tprintf("{f_tfree=%lu, f_tinode=%lu, ",
                                statbuf.f_tfree, statbuf.f_tinode);
@@ -1383,261 +1939,354 @@ struct tcb *tcp;
        }
        return 0;
 }
-
 #endif /* SUNOS4 */
 
+/* directory */
 int
-sys_pivotroot(tcp)
-struct tcb *tcp;
+sys_chdir(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-               printpath(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
 
-
-/* directory */
-int
-sys_chdir(tcp)
-struct tcb *tcp;
+static int
+decode_mkdir(struct tcb *tcp, int offset)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[offset]);
+               tprintf(", %#lo", tcp->u_arg[offset + 1]);
        }
        return 0;
 }
 
 int
-sys_mkdir(tcp)
-struct tcb *tcp;
+sys_mkdir(struct tcb *tcp)
+{
+       return decode_mkdir(tcp, 0);
+}
+
+#ifdef LINUX
+int
+sys_mkdirat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_mkdir(tcp, 1);
+}
+#endif
+
+int
+sys_link(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", %#lo", tcp->u_arg[1]);
+               tprints(", ");
+               printpath(tcp, tcp->u_arg[1]);
        }
        return 0;
 }
 
+#ifdef LINUX
 int
-sys_rmdir(tcp)
-struct tcb *tcp;
+sys_linkat(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
+               print_dirfd(tcp, tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+               print_dirfd(tcp, tcp->u_arg[2]);
+               printpath(tcp, tcp->u_arg[3]);
+               tprints(", ");
+               printfd(tcp, tcp->u_arg[4]);
        }
        return 0;
 }
+#endif
+
+#ifdef LINUX
+static const struct xlat unlinkatflags[] = {
+#ifndef AT_REMOVEDIR
+# define AT_REMOVEDIR            0x200
+#endif
+       { AT_REMOVEDIR, "AT_REMOVEDIR"  },
+       { 0,            NULL            },
+};
 
 int
-sys_fchdir(tcp)
-struct tcb *tcp;
+sys_unlinkat(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               tprintf("%ld", tcp->u_arg[0]);
+               print_dirfd(tcp, tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+               printflags(unlinkatflags, tcp->u_arg[2], "AT_???");
        }
        return 0;
 }
+#endif
 
+#ifdef LINUX
 int
-sys_chroot(tcp)
-struct tcb *tcp;
+sys_symlinkat(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               print_dirfd(tcp, tcp->u_arg[1]);
+               printpath(tcp, tcp->u_arg[2]);
        }
        return 0;
 }
+#endif
 
-int
-sys_fchroot(tcp)
-struct tcb *tcp;
+static int
+decode_readlink(struct tcb *tcp, int offset)
 {
        if (entering(tcp)) {
-               tprintf("%ld", tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[offset]);
+               tprints(", ");
+       } else {
+               if (syserror(tcp))
+                       tprintf("%#lx", tcp->u_arg[offset + 1]);
+               else
+                       /* Used to use printpathn(), but readlink
+                        * neither includes NUL in the returned count,
+                        * nor actually writes it into memory.
+                        * printpathn() would decide on printing
+                        * "..." continuation based on garbage
+                        * past return buffer's end.
+                        */
+                       printstr(tcp, tcp->u_arg[offset + 1], tcp->u_rval);
+               tprintf(", %lu", tcp->u_arg[offset + 2]);
        }
        return 0;
 }
 
 int
-sys_link(tcp)
-struct tcb *tcp;
+sys_readlink(struct tcb *tcp)
+{
+       return decode_readlink(tcp, 0);
+}
+
+#ifdef LINUX
+int
+sys_readlinkat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_readlink(tcp, 1);
+}
+#endif
+
+#ifdef LINUX
+int
+sys_renameat(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               print_dirfd(tcp, tcp->u_arg[0]);
                printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+               print_dirfd(tcp, tcp->u_arg[2]);
+               printpath(tcp, tcp->u_arg[3]);
        }
        return 0;
 }
+#endif
 
 int
-sys_unlink(tcp)
-struct tcb *tcp;
+sys_chown(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
+               printuid(", ", tcp->u_arg[2]);
        }
        return 0;
 }
 
+#ifdef LINUX
 int
-sys_symlink(tcp)
-struct tcb *tcp;
+sys_fchownat(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               print_dirfd(tcp, tcp->u_arg[0]);
                printpath(tcp, tcp->u_arg[1]);
+               printuid(", ", tcp->u_arg[2]);
+               printuid(", ", tcp->u_arg[3]);
+               tprints(", ");
+               printflags(fstatatflags, tcp->u_arg[4], "AT_???");
        }
        return 0;
 }
+#endif
 
 int
-sys_readlink(tcp)
-struct tcb *tcp;
+sys_fchown(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-       } else {
-               if (syserror(tcp))
-                       tprintf("%#lx", tcp->u_arg[1]);
-               else
-                       printpathn(tcp, tcp->u_arg[1], tcp->u_rval);
-               tprintf(", %lu", tcp->u_arg[2]);
+               printfd(tcp, tcp->u_arg[0]);
+               printuid(", ", tcp->u_arg[1]);
+               printuid(", ", tcp->u_arg[2]);
        }
        return 0;
 }
 
-int
-sys_rename(tcp)
-struct tcb *tcp;
+static int
+decode_chmod(struct tcb *tcp, int offset)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-               printpath(tcp, tcp->u_arg[1]);
+               printpath(tcp, tcp->u_arg[offset]);
+               tprintf(", %#lo", tcp->u_arg[offset + 1]);
        }
        return 0;
 }
 
 int
-sys_chown(tcp)
-struct tcb *tcp;
+sys_chmod(struct tcb *tcp)
 {
-       if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", %lu, %lu", tcp->u_arg[1], tcp->u_arg[2]);
-       }
-       return 0;
+       return decode_chmod(tcp, 0);
 }
 
+#ifdef LINUX
+int
+sys_fchmodat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_chmod(tcp, 1);
+}
+#endif
+
 int
-sys_fchown(tcp)
-struct tcb *tcp;
+sys_fchmod(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               tprintf("%ld, %lu, %lu",
-                       tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprintf(", %#lo", tcp->u_arg[1]);
        }
        return 0;
 }
 
+#ifdef ALPHA
 int
-sys_chmod(tcp)
-struct tcb *tcp;
+sys_osf_utimes(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", %#lo", tcp->u_arg[1]);
+               tprints(", ");
+               printtv_bitness(tcp, tcp->u_arg[1], BITNESS_32,  0);
        }
        return 0;
 }
+#endif
 
-int
-sys_fchmod(tcp)
-struct tcb *tcp;
+static int
+decode_utimes(struct tcb *tcp, int offset, int special)
 {
        if (entering(tcp)) {
-               tprintf("%ld, %#lo", tcp->u_arg[0], tcp->u_arg[1]);
+               printpath(tcp, tcp->u_arg[offset]);
+               tprints(", ");
+               if (tcp->u_arg[offset + 1] == 0)
+                       tprints("NULL");
+               else {
+                       tprints("{");
+                       printtv_bitness(tcp, tcp->u_arg[offset + 1],
+                                       BITNESS_CURRENT, special);
+                       tprints(", ");
+                       printtv_bitness(tcp, tcp->u_arg[offset + 1]
+                                       + sizeof(struct timeval),
+                                       BITNESS_CURRENT, special);
+                       tprints("}");
+               }
        }
        return 0;
 }
 
-#ifdef ALPHA
 int
-sys_osf_utimes(tcp)
-struct tcb *tcp;
+sys_utimes(struct tcb *tcp)
 {
-    if (entering(tcp)) {
-       printpath(tcp, tcp->u_arg[0]);
-       tprintf(", ");
-       printtv32(tcp, tcp->u_arg[1]);
-    }
-    return 0;
+       return decode_utimes(tcp, 0, 0);
+}
+
+#ifdef LINUX
+int
+sys_futimesat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_utimes(tcp, 1, 0);
 }
-#endif
 
 int
-sys_utimes(tcp)
-struct tcb *tcp;
+sys_utimensat(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
-               printtv(tcp, tcp->u_arg[1]);
+               print_dirfd(tcp, tcp->u_arg[0]);
+               decode_utimes(tcp, 1, 1);
+               tprints(", ");
+               printflags(utimensatflags, tcp->u_arg[3], "AT_???");
        }
        return 0;
 }
+#endif
 
 int
-sys_utime(tcp)
-struct tcb *tcp;
+sys_utime(struct tcb *tcp)
 {
-       long ut[2];
+       union {
+               long utl[2];
+               int uti[2];
+       } u;
 
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
-               tprintf(", ");
+               tprints(", ");
                if (!tcp->u_arg[1])
-                       tprintf("NULL");
+                       tprints("NULL");
                else if (!verbose(tcp))
                        tprintf("%#lx", tcp->u_arg[1]);
-               else if (umoven(tcp, tcp->u_arg[1], sizeof ut,
-                   (char *) ut) < 0)
-                       tprintf("[?, ?]");
-               else {
-                       tprintf("[%s,", sprinttime(ut[0]));
-                       tprintf(" %s]", sprinttime(ut[1]));
+               else if (umoven(tcp, tcp->u_arg[1],
+                               2 * personality_wordsize[current_personality],
+                               (char *) &u) < 0)
+                       tprints("[?, ?]");
+               else if (personality_wordsize[current_personality]
+                        == sizeof u.utl[0]) {
+                       tprintf("[%s,", sprinttime(u.utl[0]));
+                       tprintf(" %s]", sprinttime(u.utl[1]));
+               }
+               else if (personality_wordsize[current_personality]
+                        == sizeof u.uti[0]) {
+                       tprintf("[%s,", sprinttime(u.uti[0]));
+                       tprintf(" %s]", sprinttime(u.uti[1]));
                }
+               else
+                       abort();
        }
        return 0;
 }
 
-int
-sys_mknod(tcp)
-struct tcb *tcp;
+static int
+decode_mknod(struct tcb *tcp, int offset)
 {
-       int mode = tcp->u_arg[1];
+       int mode = tcp->u_arg[offset + 1];
 
        if (entering(tcp)) {
-               printpath(tcp, tcp->u_arg[0]);
+               printpath(tcp, tcp->u_arg[offset]);
                tprintf(", %s", sprintmode(mode));
                switch (mode & S_IFMT) {
                case S_IFCHR: case S_IFBLK:
 #ifdef LINUXSPARC
                        if (current_personality == 1)
                        tprintf(", makedev(%lu, %lu)",
-                               (unsigned long) ((tcp->u_arg[2] >> 18) & 0x3fff),
-                               (unsigned long) (tcp->u_arg[2] & 0x3ffff));
+                               (unsigned long) ((tcp->u_arg[offset + 2] >> 18) & 0x3fff),
+                               (unsigned long) (tcp->u_arg[offset + 2] & 0x3ffff));
                        else
-#endif 
+#endif
                        tprintf(", makedev(%lu, %lu)",
-                               (unsigned long) major(tcp->u_arg[2]),
-                               (unsigned long) minor(tcp->u_arg[2]));
+                               (unsigned long) major(tcp->u_arg[offset + 2]),
+                               (unsigned long) minor(tcp->u_arg[offset + 2]));
                        break;
                default:
                        break;
@@ -1647,8 +2296,24 @@ struct tcb *tcp;
 }
 
 int
-sys_mkfifo(tcp)
-struct tcb *tcp;
+sys_mknod(struct tcb *tcp)
+{
+       return decode_mknod(tcp, 0);
+}
+
+#ifdef LINUX
+int
+sys_mknodat(struct tcb *tcp)
+{
+       if (entering(tcp))
+               print_dirfd(tcp, tcp->u_arg[0]);
+       return decode_mknod(tcp, 1);
+}
+#endif
+
+#ifdef FREEBSD
+int
+sys_mkfifo(struct tcb *tcp)
 {
        if (entering(tcp)) {
                printpath(tcp, tcp->u_arg[0]);
@@ -1656,23 +2321,21 @@ struct tcb *tcp;
        }
        return 0;
 }
+#endif /* FREEBSD */
 
 int
-sys_fsync(tcp)
-struct tcb *tcp;
+sys_fsync(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               tprintf("%ld", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
        }
        return 0;
 }
 
-#ifdef linux
+#ifdef LINUX
 
 static void
-printdir(tcp, addr)
-struct tcb *tcp;
-long addr;
+printdir(struct tcb *tcp, long addr)
 {
        struct dirent d;
 
@@ -1681,21 +2344,21 @@ long addr;
                return;
        }
        if (umove(tcp, addr, &d) < 0) {
-               tprintf("{...}");
+               tprints("{...}");
                return;
        }
        tprintf("{d_ino=%ld, ", (unsigned long) d.d_ino);
-       tprintf("d_name=");
+       tprints("d_name=");
        printpathn(tcp, (long) ((struct dirent *) addr)->d_name, d.d_reclen);
-       tprintf("}");
+       tprints("}");
 }
 
 int
-sys_readdir(tcp)
-struct tcb *tcp;
+sys_readdir(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               tprintf("%lu, ", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
        } else {
                if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp))
                        tprintf("%#lx", tcp->u_arg[1]);
@@ -1708,32 +2371,33 @@ struct tcb *tcp;
        return 0;
 }
 
-#endif /* linux */
+#endif /* LINUX */
 
-#ifdef FREEBSD
-struct xlat direnttypes[] = {
-       { DT_FIFO,      "DT_FIFO"       },
-       { DT_CHR,       "DT_CHR"        },
-       { DT_DIR,       "DT_DIR"        },
-       { DT_BLK,       "DT_BLK"        },
-       { DT_REG,       "DT_REG"        },
-       { DT_LNK,       "DT_LNK"        },
-       { DT_SOCK,      "DT_SOCK"       },
-       { DT_WHT,       "DT_WHT"        },
+#if defined FREEBSD || defined LINUX
+static const struct xlat direnttypes[] = {
+       { DT_UNKNOWN,   "DT_UNKNOWN"    },
+       { DT_FIFO,      "DT_FIFO"       },
+       { DT_CHR,       "DT_CHR"        },
+       { DT_DIR,       "DT_DIR"        },
+       { DT_BLK,       "DT_BLK"        },
+       { DT_REG,       "DT_REG"        },
+       { DT_LNK,       "DT_LNK"        },
+       { DT_SOCK,      "DT_SOCK"       },
+       { DT_WHT,       "DT_WHT"        },
        { 0,            NULL            },
 };
 
 #endif
 
 int
-sys_getdents(tcp)
-struct tcb *tcp;
+sys_getdents(struct tcb *tcp)
 {
        int i, len, dents = 0;
        char *buf;
 
        if (entering(tcp)) {
-               tprintf("%lu, ", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
                return 0;
        }
        if (syserror(tcp) || !verbose(tcp)) {
@@ -1741,31 +2405,37 @@ struct tcb *tcp;
                return 0;
        }
        len = tcp->u_rval;
-       if ((buf = malloc(len)) == NULL) {
-               tprintf("out of memory\n");
-               return 0;
-       }
+       /* Beware of insanely large or negative values in tcp->u_rval */
+       if (tcp->u_rval > 1024*1024)
+               len = 1024*1024;
+       if (tcp->u_rval < 0)
+               len = 0;
+       buf = len ? malloc(len) : NULL;
+       if (len && !buf)
+               die_out_of_memory();
        if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
-               tprintf("{...}, %lu", tcp->u_arg[2]);
+               tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
                free(buf);
                return 0;
        }
        if (!abbrev(tcp))
-               tprintf("{");
+               tprints("{");
        for (i = 0; i < len;) {
                struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
-#ifdef linux
+#ifdef LINUX
                if (!abbrev(tcp)) {
                        tprintf("%s{d_ino=%lu, d_off=%lu, ",
                                i ? " " : "", d->d_ino, d->d_off);
                        tprintf("d_reclen=%u, d_name=\"%s\"}",
                                d->d_reclen, d->d_name);
                }
-#endif /* linux */
+#endif /* LINUX */
 #ifdef SVR4
                if (!abbrev(tcp)) {
                        tprintf("%s{d_ino=%lu, d_off=%lu, ",
-                               i ? " " : "", d->d_ino, d->d_off);
+                               i ? " " : "",
+                               (unsigned long) d->d_ino,
+                               (unsigned long) d->d_off);
                        tprintf("d_reclen=%u, d_name=\"%s\"}",
                                d->d_reclen, d->d_name);
                }
@@ -1787,16 +2457,16 @@ struct tcb *tcp;
                        tprintf(", d_namlen=%u, d_name=\"%.*s\"}",
                                d->d_namlen, d->d_namlen, d->d_name);
                }
-#endif /* FREEBSD */           
+#endif /* FREEBSD */
                if (!d->d_reclen) {
-                       tprintf("/* d_reclen == 0, problem here */");
+                       tprints("/* d_reclen == 0, problem here */");
                        break;
                }
                i += d->d_reclen;
                dents++;
        }
        if (!abbrev(tcp))
-               tprintf("}");
+               tprints("}");
        else
                tprintf("/* %u entries */", dents);
        tprintf(", %lu", tcp->u_arg[2]);
@@ -1807,50 +2477,55 @@ struct tcb *tcp;
 
 #if _LFS64_LARGEFILE
 int
-sys_getdents64(tcp)
-struct tcb *tcp;
+sys_getdents64(struct tcb *tcp)
 {
        int i, len, dents = 0;
        char *buf;
 
        if (entering(tcp)) {
-               tprintf("%lu, ", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
                return 0;
        }
        if (syserror(tcp) || !verbose(tcp)) {
                tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
                return 0;
        }
+
        len = tcp->u_rval;
-       if ((buf = malloc(len)) == NULL) {
-               tprintf("out of memory\n");
-               return 0;
-       }
+       /* Beware of insanely large or negative tcp->u_rval */
+       if (tcp->u_rval > 1024*1024)
+               len = 1024*1024;
+       if (tcp->u_rval < 0)
+               len = 0;
+       buf = len ? malloc(len) : NULL;
+       if (len && !buf)
+               die_out_of_memory();
+
        if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
-               tprintf("{...}, %lu", tcp->u_arg[2]);
+               tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
                free(buf);
                return 0;
        }
        if (!abbrev(tcp))
-               tprintf("{");
+               tprints("{");
        for (i = 0; i < len;) {
                struct dirent64 *d = (struct dirent64 *) &buf[i];
-#ifdef linux
-               if (!abbrev(tcp)) {
-                       tprintf("%s{d_ino=%lu, d_off=%lu, ",
-                               i ? " " : "", d->d_ino, d->d_off);
-                       tprintf("d_reclen=%u, d_name=\"%s\"}",
-                               d->d_reclen, d->d_name);
-               }
-#endif /* linux */
-#ifdef SVR4
+#if defined(LINUX) || defined(SVR4)
                if (!abbrev(tcp)) {
-                       tprintf("%s{d_ino=%llu, d_off=%llu, ",
-                               i ? " " : "", d->d_ino, d->d_off);
+                       tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64 ", ",
+                               i ? " " : "",
+                               d->d_ino,
+                               d->d_off);
+#ifdef LINUX
+                       tprints("d_type=");
+                       printxval(direnttypes, d->d_type, "DT_???");
+                       tprints(", ");
+#endif
                        tprintf("d_reclen=%u, d_name=\"%s\"}",
                                d->d_reclen, d->d_name);
                }
-#endif /* SVR4 */
+#endif /* LINUX || SVR4 */
 #ifdef SUNOS4
                if (!abbrev(tcp)) {
                        tprintf("%s{d_off=%lu, d_fileno=%lu, d_reclen=%u, ",
@@ -1860,11 +2535,15 @@ struct tcb *tcp;
                                d->d_namlen, d->d_namlen, d->d_name);
                }
 #endif /* SUNOS4 */
+               if (!d->d_reclen) {
+                       tprints("/* d_reclen == 0, problem here */");
+                       break;
+               }
                i += d->d_reclen;
                dents++;
        }
        if (!abbrev(tcp))
-               tprintf("}");
+               tprints("}");
        else
                tprintf("/* %u entries */", dents);
        tprintf(", %lu", tcp->u_arg[2]);
@@ -1872,36 +2551,42 @@ struct tcb *tcp;
        return 0;
 }
 #endif
+
 #ifdef FREEBSD
 int
-sys_getdirentries(tcp)
-struct tcb * tcp;
+sys_getdirentries(struct tcb *tcp)
 {
        int i, len, dents = 0;
        long basep;
        char *buf;
 
        if (entering(tcp)) {
-               tprintf("%lu, ", tcp->u_arg[0]);
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
                return 0;
        }
        if (syserror(tcp) || !verbose(tcp)) {
                tprintf("%#lx, %lu, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]);
                return 0;
        }
+
        len = tcp->u_rval;
-       if ((buf = malloc(len)) == NULL) {
-               tprintf("out of memory\n");
-               return 0;
-       }
+       /* Beware of insanely large or negative tcp->u_rval */
+       if (tcp->u_rval > 1024*1024)
+               len = 1024*1024;
+       if (tcp->u_rval < 0)
+               len = 0;
+       buf = malloc(len);
+       if (!buf)
+               die_out_of_memory();
+
        if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
-               tprintf("{...}, %lu, %#lx", tcp->u_arg[2], tcp->u_arg[3]);
+               tprintf("%#lx, %lu, %#lx", tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]);
                free(buf);
                return 0;
        }
        if (!abbrev(tcp))
-               tprintf("{");
+               tprints("{");
        for (i = 0; i < len;) {
                struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
                if (!abbrev(tcp)) {
@@ -1911,11 +2596,15 @@ struct tcb * tcp;
                        tprintf(", d_namlen=%u, d_name=\"%.*s\"}",
                                d->d_namlen, d->d_namlen, d->d_name);
                }
+               if (!d->d_reclen) {
+                       tprints("/* d_reclen == 0, problem here */");
+                       break;
+               }
                i += d->d_reclen;
                dents++;
        }
        if (!abbrev(tcp))
-               tprintf("}");
+               tprints("}");
        else
                tprintf("/* %u entries */", dents);
        free(buf);
@@ -1928,43 +2617,40 @@ struct tcb * tcp;
 }
 #endif
 
-#ifdef linux
+#ifdef LINUX
 int
-sys_getcwd(tcp)
-struct tcb *tcp;
+sys_getcwd(struct tcb *tcp)
 {
-    if (exiting(tcp)) {
-       if (syserror(tcp))
-           tprintf("%#lx", tcp->u_arg[0]);
-       else
-           printpathn(tcp, tcp->u_arg[0], tcp->u_rval - 1);
-       tprintf(", %lu", tcp->u_arg[1]);
-    }
-    return 0;
+       if (exiting(tcp)) {
+               if (syserror(tcp))
+                       tprintf("%#lx", tcp->u_arg[0]);
+               else
+                       printpathn(tcp, tcp->u_arg[0], tcp->u_rval - 1);
+               tprintf(", %lu", tcp->u_arg[1]);
+       }
+       return 0;
 }
-#endif /* linux */
+#endif /* LINUX */
 
 #ifdef FREEBSD
 int
-sys___getcwd(tcp)
-struct tcb *tcp;
+sys___getcwd(struct tcb *tcp)
 {
-    if (exiting(tcp)) {
-       if (syserror(tcp))
-           tprintf("%#lx", tcp->u_arg[0]);
-       else
-           printpathn(tcp, tcp->u_arg[0], tcp->u_arg[1]);
-       tprintf(", %lu", tcp->u_arg[1]);
-    }
-    return 0;
+       if (exiting(tcp)) {
+               if (syserror(tcp))
+                       tprintf("%#lx", tcp->u_arg[0]);
+               else
+                       printpathn(tcp, tcp->u_arg[0], tcp->u_arg[1]);
+               tprintf(", %lu", tcp->u_arg[1]);
+       }
+       return 0;
 }
 #endif
 
 #ifdef HAVE_SYS_ASYNCH_H
 
 int
-sys_aioread(tcp)
-struct tcb *tcp;
+sys_aioread(struct tcb *tcp)
 {
        struct aio_result_t res;
 
@@ -1988,8 +2674,7 @@ struct tcb *tcp;
 }
 
 int
-sys_aiowrite(tcp)
-struct tcb *tcp;
+sys_aiowrite(struct tcb *tcp)
 {
        struct aio_result_t res;
 
@@ -2001,7 +2686,7 @@ struct tcb *tcp;
        }
        else {
                if (tcp->u_arg[5] == 0)
-                       tprintf(", NULL");
+                       tprints(", NULL");
                else if (syserror(tcp)
                    || umove(tcp, tcp->u_arg[5], &res) < 0)
                        tprintf(", %#lx", tcp->u_arg[5]);
@@ -2013,8 +2698,7 @@ struct tcb *tcp;
 }
 
 int
-sys_aiowait(tcp)
-struct tcb *tcp;
+sys_aiowait(struct tcb *tcp)
 {
        if (entering(tcp))
                printtv(tcp, tcp->u_arg[0]);
@@ -2022,14 +2706,13 @@ struct tcb *tcp;
 }
 
 int
-sys_aiocancel(tcp)
-struct tcb *tcp;
+sys_aiocancel(struct tcb *tcp)
 {
        struct aio_result_t res;
 
        if (exiting(tcp)) {
                if (tcp->u_arg[0] == 0)
-                       tprintf("NULL");
+                       tprints("NULL");
                else if (syserror(tcp)
                    || umove(tcp, tcp->u_arg[0], &res) < 0)
                        tprintf("%#lx", tcp->u_arg[0]);
@@ -2041,3 +2724,281 @@ struct tcb *tcp;
 }
 
 #endif /* HAVE_SYS_ASYNCH_H */
+
+static const struct xlat xattrflags[] = {
+#ifdef XATTR_CREATE
+       { XATTR_CREATE,  "XATTR_CREATE" },
+       { XATTR_REPLACE, "XATTR_REPLACE" },
+#endif
+       { 0,             NULL }
+};
+
+static void
+print_xattr_val(struct tcb *tcp, int failed,
+               unsigned long arg,
+               unsigned long insize,
+               unsigned long size)
+{
+       if (!failed) {
+               unsigned long capacity = 4 * size + 1;
+               unsigned char *buf = (capacity < size) ? NULL : malloc(capacity);
+               if (buf == NULL || /* probably a bogus size argument */
+                       umoven(tcp, arg, size, (char *) &buf[3 * size]) < 0) {
+                       failed = 1;
+               }
+               else {
+                       unsigned char *out = buf;
+                       unsigned char *in = &buf[3 * size];
+                       size_t i;
+                       for (i = 0; i < size; ++i) {
+                               if (isprint(in[i]))
+                                       *out++ = in[i];
+                               else {
+#define tohex(n) "0123456789abcdef"[n]
+                                       *out++ = '\\';
+                                       *out++ = 'x';
+                                       *out++ = tohex(in[i] / 16);
+                                       *out++ = tohex(in[i] % 16);
+                               }
+                       }
+                       /* Don't print terminating NUL if there is one.  */
+                       if (i > 0 && in[i - 1] == '\0')
+                               out -= 4;
+                       *out = '\0';
+                       tprintf(", \"%s\", %ld", buf, insize);
+               }
+               free(buf);
+       }
+       if (failed)
+               tprintf(", 0x%lx, %ld", arg, insize);
+}
+
+int
+sys_setxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printpath(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+               print_xattr_val(tcp, 0, tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[3]);
+               tprints(", ");
+               printflags(xattrflags, tcp->u_arg[4], "XATTR_???");
+       }
+       return 0;
+}
+
+int
+sys_fsetxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+               print_xattr_val(tcp, 0, tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[3]);
+               tprints(", ");
+               printflags(xattrflags, tcp->u_arg[4], "XATTR_???");
+       }
+       return 0;
+}
+
+int
+sys_getxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printpath(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+       } else {
+               print_xattr_val(tcp, syserror(tcp), tcp->u_arg[2], tcp->u_arg[3],
+                               tcp->u_rval);
+       }
+       return 0;
+}
+
+int
+sys_fgetxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+       } else {
+               print_xattr_val(tcp, syserror(tcp), tcp->u_arg[2], tcp->u_arg[3],
+                               tcp->u_rval);
+       }
+       return 0;
+}
+
+int
+sys_listxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printpath(tcp, tcp->u_arg[0]);
+       } else {
+               /* XXX Print value in format */
+               tprintf(", %p, %lu", (void *) tcp->u_arg[1], tcp->u_arg[2]);
+       }
+       return 0;
+}
+
+int
+sys_flistxattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+       } else {
+               /* XXX Print value in format */
+               tprintf(", %p, %lu", (void *) tcp->u_arg[1], tcp->u_arg[2]);
+       }
+       return 0;
+}
+
+int
+sys_removexattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printpath(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+       }
+       return 0;
+}
+
+int
+sys_fremovexattr(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printstr(tcp, tcp->u_arg[1], -1);
+       }
+       return 0;
+}
+
+
+static const struct xlat advise[] = {
+  { POSIX_FADV_NORMAL,         "POSIX_FADV_NORMAL"     },
+  { POSIX_FADV_RANDOM,         "POSIX_FADV_RANDOM"     },
+  { POSIX_FADV_SEQUENTIAL,     "POSIX_FADV_SEQUENTIAL" },
+  { POSIX_FADV_WILLNEED,       "POSIX_FADV_WILLNEED"   },
+  { POSIX_FADV_DONTNEED,       "POSIX_FADV_DONTNEED"   },
+  { POSIX_FADV_NOREUSE,                "POSIX_FADV_NOREUSE"    },
+  { 0,                         NULL                    }
+};
+
+
+#ifdef LINUX
+int
+sys_fadvise64(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               int argn;
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               argn = printllval(tcp, "%lld", 1);
+               tprintf(", %ld, ", tcp->u_arg[argn++]);
+               printxval(advise, tcp->u_arg[argn], "POSIX_FADV_???");
+       }
+       return 0;
+}
+#endif
+
+
+int
+sys_fadvise64_64(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               int argn;
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+#if defined ARM || defined POWERPC
+               argn = printllval(tcp, "%lld, ", 2);
+#else
+               argn = printllval(tcp, "%lld, ", 1);
+#endif
+               argn = printllval(tcp, "%lld, ", argn);
+#if defined ARM || defined POWERPC
+               printxval(advise, tcp->u_arg[1], "POSIX_FADV_???");
+#else
+               printxval(advise, tcp->u_arg[argn], "POSIX_FADV_???");
+#endif
+       }
+       return 0;
+}
+
+#ifdef LINUX
+static const struct xlat inotify_modes[] = {
+       { 0x00000001,   "IN_ACCESS"     },
+       { 0x00000002,   "IN_MODIFY"     },
+       { 0x00000004,   "IN_ATTRIB"     },
+       { 0x00000008,   "IN_CLOSE_WRITE"},
+       { 0x00000010,   "IN_CLOSE_NOWRITE"},
+       { 0x00000020,   "IN_OPEN"       },
+       { 0x00000040,   "IN_MOVED_FROM" },
+       { 0x00000080,   "IN_MOVED_TO"   },
+       { 0x00000100,   "IN_CREATE"     },
+       { 0x00000200,   "IN_DELETE"     },
+       { 0x00000400,   "IN_DELETE_SELF"},
+       { 0x00000800,   "IN_MOVE_SELF"  },
+       { 0x00002000,   "IN_UNMOUNT"    },
+       { 0x00004000,   "IN_Q_OVERFLOW" },
+       { 0x00008000,   "IN_IGNORED"    },
+       { 0x01000000,   "IN_ONLYDIR"    },
+       { 0x02000000,   "IN_DONT_FOLLOW"},
+       { 0x20000000,   "IN_MASK_ADD"   },
+       { 0x40000000,   "IN_ISDIR"      },
+       { 0x80000000,   "IN_ONESHOT"    },
+       { 0,            NULL            }
+};
+
+static const struct xlat inotify_init_flags[] = {
+       { 0x00000800,   "IN_NONBLOCK"   },
+       { 0x00080000,   "IN_CLOEXEC"    },
+       { 0,            NULL            }
+};
+
+int
+sys_inotify_add_watch(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprints(", ");
+               printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+               printflags(inotify_modes, tcp->u_arg[2], "IN_???");
+       }
+       return 0;
+}
+
+int
+sys_inotify_rm_watch(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               printfd(tcp, tcp->u_arg[0]);
+               tprintf(", %ld", tcp->u_arg[1]);
+       }
+       return 0;
+}
+
+int
+sys_inotify_init1(struct tcb *tcp)
+{
+       if (entering(tcp))
+               printflags(inotify_init_flags, tcp->u_arg[0], "IN_???");
+       return 0;
+}
+
+int
+sys_fallocate(struct tcb *tcp)
+{
+       if (entering(tcp)) {
+               int argn;
+               printfd(tcp, tcp->u_arg[0]);            /* fd */
+               tprints(", ");
+               tprintf("%#lo, ", tcp->u_arg[1]);       /* mode */
+               argn = printllval(tcp, "%llu, ", 2);    /* offset */
+               printllval(tcp, "%llu", argn);          /* len */
+       }
+       return 0;
+}
+#endif