PATCH: Add x32 support to strace

H.J. Lu hongjiu.lu at intel.com
Mon Apr 16 02:09:02 UTC 2012


On Sun, Apr 15, 2012 at 01:47:01PM -0700, H.J. Lu wrote:
> Hi,
> 
> X32:
> 
> https://sites.google.com/site/x32abi/
> 
> support is added to Linux kernel 3.4. In a nutshell, x32 is x86-64 with
> 32bit pointers.  At system call level, x32 is also identical to x86-64,
> as shown by many changes like "defined(X86_64) || defined(X32)".  The
> main differerence bewteen x32 and x86-64 is off_t in x32 is long long
> instead of long.
> 
> This patch adds x32 support to strace.  Tested on Linux/x32.
> 
> Thanks.
> 
> 

This version of patch uses AC_TRY_COMPILE in configure.ac.


H.J.
----
2012-04-15  H.J. Lu  <hongjiu.lu at intel.com>

	* configure.ac: Support X32.

	* defs.h (SUPPORTED_PERSONALITIES): Set to 3 for X86_64.
	Defined to 1 for X32.
	(PERSONALITY2_WORDSIZE): Set to 4 for X86_64.
	(PERSONALITY0_WORDSIZE): Defined to 4 for X32.
	(tcb): Add ext_arg for X32.

	* file.c (stat): New for X32.
	(sys_lseek): Use 64-bit version for X32.
	(printstat64): Check current_personality != 1 for X86_64.

	* ipc.c (indirect_ipccall): Check current_personality == 1
	for X86_64.

	* mem.c (sys_mmap64): Also use tcp->u_arg for X32.  Print NULL
	for zero address.  Call printllval for offset for X32.

	* pathtrace.c (pathtrace_match): Don't check sys_old_mmap for
	X32.

	* process.c (ARG_FLAGS): Defined for X32.
	(ARG_STACK): Likewise.
	(ARG_PTID): Likewise.
	(change_syscall): Handle X32.
	(struct_user_offsets): Support X32.
	(sys_arch_prctl): Likewise.

	* signal.c: Include <asm/sigcontext.h> for X32.
	(SA_RESTORER): Also define for X32.

	* syscall.c (update_personality): Support X32 for X86_64.
	(is_restart_error): Likewise.
	(syscall_fixup_on_sysenter): Likewise.
	(get_syscall_args): Likewise.
	(get_syscall_result): Likewise.
	(get_error): Likewise.
	(__X32_SYSCALL_BIT): Define if not defined.
	(__X32_SYSCALL_MASK): Likewise.
	(get_scno): Check DS register value for X32.  Use
	__X32_SYSCALL_MASK on X32 system calls.

	* util.c (printllval): Use ext_arg for X32.
	(printcall): Support X32.
	(change_syscall): Likewise.
	(arg0_offset): Likewise.
	(arg1_offset): Likewise.

	* Makefile.am (EXTRA_DIST): Add linux/x32/errnoent.h,
	linux/x32/ioctlent.h.in, linux/x32/signalent.h,
	linux/x32/syscallent.h, linux/x86_64/errnoent2.h,
	linux/x86_64/ioctlent2.h, linux/x86_64/signalent2.h and
	linux/x86_64/syscallent2.h.

	* linux/x32/errnoent.h: New.
	* linux/x32/ioctlent.h.in: Likewise.
	* linux/x32/signalent.h: Likewise.
	* linux/x32/syscallent.h: Likewise.
	* linux/x86_64/errnoent2.h: Likewise.
	* linux/x86_64/ioctlent2.h: Likewise.
	* linux/x86_64/signalent2.h: Likewise.
	* linux/x86_64/syscallent2.h: Likewise.

diff --git a/Makefile.am b/Makefile.am
index 8edcf89..bbc5790 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,10 +78,14 @@ EXTRA_DIST = $(man_MANS) errnoent.sh signalent.sh syscallent.sh ioctlsort.c \
 	     linux/sparc64/syscallent.h linux/sparc64/syscallent1.h \
 	     linux/sparc64/syscallent2.h \
 	     linux/tile/ioctlent.h.in linux/tile/syscallent.h \
+	     linux/x32/errnoent.h linux/x32/ioctlent.h.in \
+	     linux/x32/signalent.h linux/x32/syscallent.h \
 	     linux/x86_64/ioctlent.h.in linux/x86_64/syscallent.h \
 	     linux/x86_64/gentab.pl \
 	     linux/x86_64/errnoent1.h linux/x86_64/ioctlent1.h \
 	     linux/x86_64/signalent1.h linux/x86_64/syscallent1.h \
+	     linux/x86_64/errnoent2.h linux/x86_64/ioctlent2.h \
+	     linux/x86_64/signalent2.h linux/x86_64/syscallent2.h \
 	     xlate.el
 
 .PHONY: srpm
diff --git a/configure.ac b/configure.ac
index 86d1de2..f55b8a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,11 @@ AM_INIT_AUTOMAKE([foreign check-news dist-xz no-dist-gzip silent-rules])
 AM_MAINTAINER_MODE
 AC_CANONICAL_HOST
 
+AC_PROG_CC
+AC_GNU_SOURCE
+
+AC_USE_SYSTEM_EXTENSIONS
+
 AC_MSG_CHECKING([for supported architecture])
 case "$host_cpu" in
 bfin)
@@ -78,8 +83,15 @@ sh*)
 	AC_DEFINE([SH], 1, [Define for the SH architecture.])
 	;;
 x86?64*)
-	arch=x86_64
-	AC_DEFINE([X86_64], 1, [Define for the AMD x86-64 architecture.])
+	AC_TRY_COMPILE(
+[#ifndef __ILP32__
+# error not x32
+#endif], [], arch=x32, arch=x86_64)
+	if test "$arch" = "x86_64"; then
+		AC_DEFINE([X86_64], 1, [Define for the 64bit AMD x86-64 architecture.])
+	else
+		AC_DEFINE([X32], 1, [Define for the 32bit AMD x86-64 architecture.])
+	fi
 	;;
 cris|crisv10)
 	arch=crisv10
@@ -108,9 +120,7 @@ AC_SUBST(arch)
 
 AM_CONDITIONAL([I386], [test x$arch = xi386])
 AM_CONDITIONAL([X86_64], [test x$arch = xx86_64])
-
-AC_PROG_CC
-AC_GNU_SOURCE
+AM_CONDITIONAL([X32], [test x$arch = xx32])
 
 AC_INCLUDEDIR
 
diff --git a/defs.h b/defs.h
index 1ebbd29..3705f59 100644
--- a/defs.h
+++ b/defs.h
@@ -153,7 +153,7 @@ extern long ptrace(int, int, char *, long);
 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
 # define PTRACE_POKEUSER PTRACE_POKEUSR
 #endif
-#if defined(X86_64) || defined(I386)
+#if defined(X86_64) || defined(X32) || defined(I386)
 /* For struct pt_regs. x86 strace uses PTRACE_GETREGS.
  * PTRACE_GETREGS returns registers in the layout of this struct.
  */
@@ -221,9 +221,16 @@ extern long ptrace(int, int, char *, long);
 
 #ifdef X86_64
 # undef SUPPORTED_PERSONALITIES
-# define SUPPORTED_PERSONALITIES 2
+# define SUPPORTED_PERSONALITIES 3
 # define PERSONALITY0_WORDSIZE 8
 # define PERSONALITY1_WORDSIZE 4
+# define PERSONALITY2_WORDSIZE 4
+#endif
+
+#ifdef X32
+# undef SUPPORTED_PERSONALITIES
+# define SUPPORTED_PERSONALITIES 1
+# define PERSONALITY0_WORDSIZE 4
 #endif
 
 #ifdef ARM
@@ -324,10 +331,13 @@ struct tcb {
 	int u_error;		/* Error code */
 	long scno;		/* System call number */
 	long u_arg[MAX_ARGS];	/* System call arguments */
-#if defined(LINUX_MIPSN32)
+#if defined(LINUX_MIPSN32) || defined(X32)
 	long long ext_arg[MAX_ARGS];	/* System call arguments */
 #endif
 	long u_rval;		/* (first) return value */
+#ifdef HAVE_LONG_LONG
+	long long u_lrval;	/* long long return value */
+#endif
 #if SUPPORTED_PERSONALITIES > 1
 	int currpers;		/* Personality at the time of scno update */
 #endif
@@ -418,7 +428,11 @@ extern const struct xlat open_access_modes[];
 #define RVAL_HEX	001	/* hex format */
 #define RVAL_OCTAL	002	/* octal format */
 #define RVAL_UDECIMAL	003	/* unsigned decimal format */
-#define RVAL_MASK	003	/* mask for these values */
+#define RVAL_LDECIMAL	004	/* long decimal format */
+#define RVAL_LHEX	005	/* long hex format */
+#define RVAL_LOCTAL	006	/* long octal format */
+#define RVAL_LUDECIMAL	007	/* long unsigned decimal format */
+#define RVAL_MASK	007	/* mask for these values */
 
 #define RVAL_STR	010	/* Print `auxstr' field after return val */
 #define RVAL_NONE	020	/* Print nothing */
diff --git a/file.c b/file.c
index 1a448cd..5f3b506 100644
--- a/file.c
+++ b/file.c
@@ -73,6 +73,29 @@ struct stat_sparc64 {
 # define stat kernel_stat
 # include <asm/stat.h>
 # undef stat
+#elif defined(X32)
+struct stat {
+	unsigned long long	st_dev;
+	unsigned long long	st_ino;
+	unsigned long long	st_nlink;
+
+	unsigned int		st_mode;
+	unsigned int		st_uid;
+	unsigned int		st_gid;
+	unsigned int		__pad0;
+	unsigned long long	st_rdev;
+	long long		st_size;
+	long long		st_blksize;
+	long long		st_blocks;
+
+	unsigned long long	st_atime;
+	unsigned long long	st_atime_nsec;
+	unsigned long long	st_mtime;
+	unsigned long long	st_mtime_nsec;
+	unsigned long long	st_ctime;
+	unsigned long long	st_ctime_nsec;
+	long long		__unused[3];
+};
 #else
 # undef dev_t
 # undef ino_t
@@ -478,8 +501,7 @@ static const struct xlat whence[] = {
 	{ 0,		NULL		},
 };
 
-#if !defined(HAVE_LONG_LONG_OFF_T)
-# if defined(LINUX_MIPSN32)
+#if defined(LINUX_MIPSN32) || defined(X32)
 int
 sys_lseek(struct tcb *tcp)
 {
@@ -497,9 +519,9 @@ sys_lseek(struct tcb *tcp)
 			tprintf("%lld, ", offset);
 		printxval(whence, _whence, "SEEK_???");
 	}
-	return RVAL_UDECIMAL;
+	return RVAL_LUDECIMAL;
 }
-# else /* !LINUX_MIPSN32 */
+#else
 int
 sys_lseek(struct tcb *tcp)
 {
@@ -519,7 +541,6 @@ sys_lseek(struct tcb *tcp)
 	}
 	return RVAL_UDECIMAL;
 }
-# endif
 #endif
 
 int
@@ -1034,7 +1055,7 @@ printstat64(struct tcb *tcp, long addr)
 #endif /* LINUXSPARC */
 
 #if defined X86_64
-	if (current_personality == 0) {
+	if (current_personality != 1) {
 		printstat(tcp, addr);
 		return;
 	}
diff --git a/ipc.c b/ipc.c
index 34e32a3..f4ec522 100644
--- a/ipc.c
+++ b/ipc.c
@@ -169,7 +169,7 @@ static int
 indirect_ipccall(struct tcb *tcp)
 {
 #ifdef X86_64
-	return current_personality > 0;
+	return current_personality == 1;
 #endif
 #if defined IA64
 	return tcp->scno < 1024; /* ia32 emulation syscalls are low */
diff --git a/linux/x32/errnoent.h b/linux/x32/errnoent.h
new file mode 100644
index 0000000..00de57b
--- /dev/null
+++ b/linux/x32/errnoent.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "../errnoent.h"
diff --git a/linux/x32/ioctlent.h.in b/linux/x32/ioctlent.h.in
new file mode 100644
index 0000000..52ac99b
--- /dev/null
+++ b/linux/x32/ioctlent.h.in
@@ -0,0 +1 @@
+#include "../i386/ioctlent.h.in"
diff --git a/linux/x32/signalent.h b/linux/x32/signalent.h
new file mode 100644
index 0000000..6fbcab1
--- /dev/null
+++ b/linux/x32/signalent.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "../signalent.h"
diff --git a/linux/x32/syscallent.h b/linux/x32/syscallent.h
new file mode 100644
index 0000000..fcb6a23
--- /dev/null
+++ b/linux/x32/syscallent.h
@@ -0,0 +1,344 @@
+	{ 3,	TD,	sys_read,		"read"		},  /* 0 */
+	{ 3,	TD,	sys_write,		"write"		},  /* 1 */
+	{ 3,	TD|TF,	sys_open,		"open"		},  /* 2 */
+	{ 1,	TD,	sys_close,		"close"		},  /* 3 */
+	{ 2,	TF,	sys_stat,		"stat"		},  /* 4 */
+	{ 2,	TD,	sys_fstat,		"fstat"		},  /* 5 */
+	{ 2,	TF,	sys_lstat,		"lstat"		},  /* 6 */
+	{ 3,	TD,	sys_poll,		"poll"		},  /* 7 */
+	{ 3,	TD,	sys_lseek,		"lseek"		},  /* 8 */
+	{ 6,	TD,	sys_mmap,		"mmap"		},  /* 9 */
+	{ 3,	0,	sys_mprotect,		"mprotect"	},  /* 10 */
+	{ 2,	0,	sys_munmap,		"munmap"	},  /* 11 */
+	{ 1,	0,	sys_brk,		"brk"		},  /* 12 */
+	{ },							    /* 13 */
+	{ 4,	TS,	sys_rt_sigprocmask,	"rt_sigprocmask"},  /* 14 */
+	{ },							    /* 15 */
+	{ },							    /* 16 */
+	{ 5,	TD,	sys_pread,		"pread"		},  /* 17 */
+	{ 5,	TD,	sys_pwrite,		"pwrite"	},  /* 18 */
+	{ },							    /* 19 */
+	{ },							    /* 20 */
+	{ 2,	TF,	sys_access,		"access"	},  /* 21 */
+	{ 1,	TD,	sys_pipe,		"pipe"		},  /* 22 */
+	{ 5,	TD,	sys_select,		"select"	},  /* 23 */
+	{ 0,	0,	sys_sched_yield,	"sched_yield"	},  /* 24 */
+	{ 5,	0,	sys_mremap,		"mremap"	},  /* 25 */
+	{ 3,	0,	sys_msync,		"msync"		},  /* 26 */
+	{ 3,	0,	sys_mincore,		"mincore"	},  /* 27 */
+	{ 3,	0,	sys_madvise,		"madvise"	},  /* 28 */
+	{ 4,	TI,	sys_shmget,		"shmget"	},  /* 29 */
+	{ 4,	TI,	sys_shmat,		"shmat"		},  /* 30 */
+	{ 4,	TI,	sys_shmctl,		"shmctl"	},  /* 31 */
+	{ 1,	TD,	sys_dup,		"dup"		},  /* 32 */
+	{ 2,	TD,	sys_dup2,		"dup2"		},  /* 33 */
+	{ 0,	TS,	sys_pause,		"pause"		},  /* 34 */
+	{ 2,	0,	sys_nanosleep,		"nanosleep"	},  /* 35 */
+	{ 2,	0,	sys_getitimer,		"getitimer"	},  /* 36 */
+	{ 1,	0,	sys_alarm,		"alarm"		},  /* 37 */
+	{ 3,	0,	sys_setitimer,		"setitimer"	},  /* 38 */
+	{ 0,	0,	sys_getpid,		"getpid"	},  /* 39 */
+	{ 4,	TD|TN,	sys_sendfile,		"sendfile"	},  /* 40 */
+	{ 3,	TN,	sys_socket,		"socket"	},  /* 41 */
+	{ 3,	TN,	sys_connect,		"connect"	},  /* 42 */
+	{ 3,	TN,	sys_accept,		"accept"	},  /* 43 */
+	{ 6,	TN,	sys_sendto,		"sendto"	},  /* 44 */
+	{ },							    /* 45 */
+	{ },							    /* 46 */
+	{ },							    /* 47 */
+	{ 2,	TN,	sys_shutdown,		"shutdown"	},  /* 48 */
+	{ 3,	TN,	sys_bind,		"bind"		},  /* 49 */
+	{ 2,	TN,	sys_listen,		"listen"	},  /* 50 */
+	{ 3,	TN,	sys_getsockname,	"getsockname"	},  /* 51 */
+	{ 3,	TN,	sys_getpeername,	"getpeername"	},  /* 52 */
+	{ 4,	TN,	sys_socketpair,		"socketpair"	},  /* 53 */
+	{ 5,	TN,	sys_setsockopt,		"setsockopt"	},  /* 54 */
+	{ 5,	TN,	sys_getsockopt,		"getsockopt"	},  /* 55 */
+	{ 5,	TP,	sys_clone,		"clone"		},  /* 56 */
+	{ 0,	TP,	sys_fork,		"fork"		},  /* 57 */
+	{ 0,	TP,	sys_vfork,		"vfork"		},  /* 58 */
+	{ },							    /* 47 */
+	{ 1,	TP,	sys_exit,		"_exit"		},  /* 60 */
+	{ 4,	TP,	sys_wait4,		"wait4"		},  /* 61 */
+	{ 2,	TS,	sys_kill,		"kill"		},  /* 62 */
+	{ 1,	0,	sys_uname,		"uname"		},  /* 63 */
+	{ 4,	TI,	sys_semget,		"semget"	},  /* 64 */
+	{ 4,	TI,	sys_semop,		"semop"		},  /* 65 */
+	{ 4,	TI,	sys_semctl,		"semctl"	},  /* 66 */
+	{ 4,	TI,	sys_shmdt,		"shmdt"		},  /* 67 */
+	{ 4,	TI,	sys_msgget,		"msgget"	},  /* 68 */
+	{ 4,	TI,	sys_msgsnd,		"msgsnd"	},  /* 69 */
+	{ 5,	TI,	sys_msgrcv,		"msgrcv"	},  /* 70 */
+	{ 3,	TI,	sys_msgctl,		"msgctl"	},  /* 71 */
+	{ 3,	TD,	sys_fcntl,		"fcntl"		},  /* 72 */
+	{ 2,	TD,	sys_flock,		"flock"		},  /* 73 */
+	{ 1,	TD,	sys_fsync,		"fsync"		},  /* 74 */
+	{ 1,	TD,	sys_fdatasync,		"fdatasync"	},  /* 75 */
+	{ 2,	TF,	sys_truncate,		"truncate"	},  /* 76 */
+	{ 2,	TD,	sys_ftruncate,		"ftruncate"	},  /* 77 */
+	{ },							    /* 78 */
+	{ 2,	TF,	sys_getcwd,		"getcwd"	},  /* 79 */
+	{ 1,	TF,	sys_chdir,		"chdir"		},  /* 80 */
+	{ 1,	TD,	sys_fchdir,		"fchdir"	},  /* 81 */
+	{ 2,	TF,	sys_rename,		"rename"	},  /* 82 */
+	{ 2,	TF,	sys_mkdir,		"mkdir"		},  /* 83 */
+	{ 1,	TF,	sys_rmdir,		"rmdir"		},  /* 84 */
+	{ 2,	TD|TF,	sys_creat,		"creat"		},  /* 85 */
+	{ 2,	TF,	sys_link,		"link"		},  /* 86 */
+	{ 1,	TF,	sys_unlink,		"unlink"	},  /* 87 */
+	{ 2,	TF,	sys_symlink,		"symlink"	},  /* 88 */
+	{ 3,	TF,	sys_readlink,		"readlink"	},  /* 89 */
+	{ 2,	TF,	sys_chmod,		"chmod"		},  /* 90 */
+	{ 2,	TD,	sys_fchmod,		"fchmod"	},  /* 91 */
+	{ 3,	TF,	sys_chown,		"chown"		},  /* 92 */
+	{ 3,	TD,	sys_fchown,		"fchown"	},  /* 93 */
+	{ 3,	TF,	sys_chown,		"lchown"	},  /* 94 */
+	{ 1,	0,	sys_umask,		"umask"		},  /* 95 */
+	{ 2,	0,	sys_gettimeofday,	"gettimeofday"	},  /* 96 */
+	{ 2,	0,	sys_getrlimit,		"getrlimit"	},  /* 97 */
+	{ 2,	0,	sys_getrusage,		"getrusage"	},  /* 98 */
+	{ 1,	0,	sys_sysinfo,		"sysinfo"	},  /* 99 */
+	{ 1,	0,	sys_times,		"times"		},  /* 100 */
+	{ },							    /* 101 */
+	{ 0,	NF,	sys_getuid,		"getuid"	},  /* 102 */
+	{ 3,	0,	sys_syslog,		"syslog"	},  /* 103 */
+	{ 0,	NF,	sys_getgid,		"getgid"	},  /* 104 */
+	{ 1,	0,	sys_setuid,		"setuid"	},  /* 105 */
+	{ 1,	0,	sys_setgid,		"setgid"	},  /* 106 */
+	{ 0,	NF,	sys_geteuid,		"geteuid"	},  /* 107 */
+	{ 0,	NF,	sys_getegid,		"getegid"	},  /* 108 */
+	{ 2,	0,	sys_setpgid,		"setpgid"	},  /* 109 */
+	{ 0,	0,	sys_getppid,		"getppid"	},  /* 110 */
+	{ 0,	0,	sys_getpgrp,		"getpgrp"	},  /* 111 */
+	{ 0,	0,	sys_setsid,		"setsid"	},  /* 112 */
+	{ 2,	0,	sys_setreuid,		"setreuid"	},  /* 113 */
+	{ 2,	0,	sys_setregid,		"setregid"	},  /* 114 */
+	{ 2,	0,	sys_getgroups,		"getgroups"	},  /* 115 */
+	{ 2,	0,	sys_setgroups,		"setgroups"	},  /* 116 */
+	{ 3,	0,	sys_setresuid,		"setresuid"	},  /* 117 */
+	{ 3,	0,	sys_getresuid,		"getresuid"	},  /* 118 */
+	{ 3,	0,	sys_setresgid,		"setresgid"	},  /* 119 */
+	{ 3,	0,	sys_getresgid,		"getresgid"	},  /* 120 */
+	{ 1,	0,	sys_getpgid,		"getpgid"	},  /* 121 */
+	{ 1,	NF,	sys_setfsuid,		"setfsuid"	},  /* 122 */
+	{ 1,	NF,	sys_setfsgid,		"setfsgid"	},  /* 123 */
+	{ 1,	0,	sys_getsid,		"getsid"	},  /* 124 */
+	{ 2,	0,	sys_capget,		"capget"	},  /* 125 */
+	{ 2,	0,	sys_capset,		"capset"	},  /* 126 */
+	{ },							    /* 127 */
+	{ },							    /* 128 */
+	{ },							    /* 129 */
+	{ 2,	TS,	sys_rt_sigsuspend,	"rt_sigsuspend"	},  /* 130 */
+	{ },							    /* 131 */
+	{ 2,	TF,	sys_utime,		"utime"		},  /* 132 */
+	{ 3,	TF,	sys_mknod,		"mknod"		},  /* 133 */
+	{ },							    /* 134 */
+	{ 1,	0,	sys_personality,	"personality"	},  /* 135 */
+	{ 2,	0,	sys_ustat,		"ustat"		},  /* 136 */
+	{ 2,	TF,	sys_statfs,		"statfs"	},  /* 137 */
+	{ 2,	TD,	sys_fstatfs,		"fstatfs"	},  /* 138 */
+	{ 3,	0,	sys_sysfs,		"sysfs"		},  /* 139 */
+	{ 2,	0,	sys_getpriority,	"getpriority"	},  /* 140 */
+	{ 3,	0,	sys_setpriority,	"setpriority"	},  /* 141 */
+	{ 0,	0,	sys_sched_setparam,	"sched_setparam"	},  /* 142 */
+	{ 2,	0,	sys_sched_getparam,	"sched_getparam"	},  /* 143 */
+	{ 3,	0,	sys_sched_setscheduler,	"sched_setscheduler"	},  /* 144 */
+	{ 1,	0,	sys_sched_getscheduler,	"sched_getscheduler"	},  /* 145 */
+	{ 1,	0,	sys_sched_get_priority_max,	"sched_get_priority_max"	},  /* 146 */
+	{ 1,	0,	sys_sched_get_priority_min,	"sched_get_priority_min"	},  /* 147 */
+	{ 2,	0,	sys_sched_rr_get_interval,	"sched_rr_get_interval"	},  /* 148 */
+	{ 2,	0,	sys_mlock,		"mlock"		},  /* 149 */
+	{ 2,	0,	sys_munlock,		"munlock"	},  /* 150 */
+	{ 1,	0,	sys_mlockall,		"mlockall"	},  /* 151 */
+	{ 0,	0,	sys_munlockall,		"munlockall"	},  /* 152 */
+	{ 0,	0,	sys_vhangup,		"vhangup"	},  /* 153 */
+	{ 3,	0,	sys_modify_ldt,		"modify_ldt"	},  /* 154 */
+	{ 2,	TF,	sys_pivotroot,		"pivot_root"	},  /* 155 */
+	{ },							    /* 156 */
+	{ 5,	0,	sys_prctl,		"prctl"		},  /* 157 */
+	{ 2,	TP,	sys_arch_prctl,		"arch_prctl"	},  /* 158 */
+	{ 1,	0,	sys_adjtimex,		"adjtimex"	},  /* 159 */
+	{ 2,	0,	sys_setrlimit,		"setrlimit"	},  /* 160 */
+	{ 1,	TF,	sys_chroot,		"chroot"	},  /* 161 */
+	{ 0,	0,	sys_sync,		"sync"		},  /* 162 */
+	{ 1,	TF,	sys_acct,		"acct"		},  /* 163 */
+	{ 2,	0,	sys_settimeofday,	"settimeofday"	},  /* 164 */
+	{ 5,	TF,	sys_mount,		"mount"		},  /* 165 */
+	{ 2,	TF,	sys_umount2,		"umount"	}, /* 166 */
+	{ 2,	TF,	sys_swapon,		"swapon"	},  /* 167 */
+	{ 1,	TF,	sys_swapoff,		"swapoff"	},  /* 168 */
+	{ 4,	0,	sys_reboot,		"reboot"	},  /* 169 */
+	{ 2,	0,	sys_sethostname,	"sethostname"	},  /* 170 */
+	{ 2,	0,	sys_setdomainname,	"setdomainname"	},  /* 171 */
+	{ 1,	0,	sys_iopl,		"iopl"		},  /* 172 */
+	{ 3,	0,	sys_ioperm,		"ioperm"	},  /* 173 */
+	{ 2,	0,	sys_create_module,	"create_module"	},  /* 174 */
+	{ 3,	0,	sys_init_module,	"init_module"	},  /* 175 */
+	{ 2,	0,	sys_delete_module,	"delete_module"	},  /* 176 */
+	{ },							    /* 177 */
+	{ },							    /* 178 */
+	{ 4,	0,	sys_quotactl,		"quotactl"	},  /* 179 */
+	{ },							    /* 180 */
+	{ },							    /* 181 */
+	{ },							    /* 182 */
+	{ },							    /* 183 */
+	{ },							    /* 184 */
+	{ },							    /* 185 */
+	{ 0,	0,	sys_gettid,		"gettid"	}, /* 186 */
+	{ 4,	TD,	sys_readahead,		"readahead"	}, /* 187 */
+	{ 5,	TF,	sys_setxattr,		"setxattr"	}, /* 188 */
+	{ 5,	TF,	sys_setxattr,		"lsetxattr"	}, /* 189 */
+	{ 5,	TD,	sys_fsetxattr,		"fsetxattr"	}, /* 190 */
+	{ 4,	TF,	sys_getxattr,		"getxattr"	}, /* 191 */
+	{ 4,	TF,	sys_getxattr,		"lgetxattr"	}, /* 192 */
+	{ 4,	TD,	sys_fgetxattr,		"fgetxattr"	}, /* 193 */
+	{ 3,	TF,	sys_listxattr,		"listxattr"	}, /* 194 */
+	{ 3,	TF,	sys_listxattr,		"llistxattr"	}, /* 195 */
+	{ 3,	TD,	sys_flistxattr,		"flistxattr"	}, /* 196 */
+	{ 2,	TF,	sys_removexattr,	"removexattr"	}, /* 197 */
+	{ 2,	TF,	sys_removexattr,	"lremovexattr"	}, /* 198 */
+	{ 2,	TD,	sys_fremovexattr,	"fremovexattr"	}, /* 199 */
+	{ 2,	TS,	sys_kill,		"tkill"		}, /* 200 */
+	{ 1,	0,	sys_time,		"time"		},  /* 201 */
+	{ 6,	0,	sys_futex,		"futex"		}, /* 202 */
+	{ 3,	0,	sys_sched_setaffinity,	"sched_setaffinity" },/* 203 */
+	{ 3,	0,	sys_sched_getaffinity,	"sched_getaffinity" },/* 204 */
+	{ },							   /* 205 */
+	{ 2,	0,	sys_io_setup,		"io_setup"	}, /* 206 */
+	{ 1,	0,	sys_io_destroy,		"io_destroy"	}, /* 207 */
+	{ 5,	0,	sys_io_getevents,	"io_getevents"	}, /* 208 */
+	{ 3,	0,	sys_io_submit,		"io_submit"	}, /* 209 */
+	{ 3,	0,	sys_io_cancel,		"io_cancel"	}, /* 210 */
+	{ },							   /* 211 */
+	{ 4,	0,	sys_lookup_dcookie,	"lookup_dcookie"}, /* 212 */
+	{ 1,	TD,	sys_epoll_create,	"epoll_create"	}, /* 213 */
+	{ },							   /* 214 */
+	{ },							   /* 215 */
+	{ 5,	0,	sys_remap_file_pages,	"remap_file_pages"}, /* 216 */
+	{ 3,	TD,	sys_getdents64,		"getdents64"	}, /* 217 */
+	{ 1,	0,	sys_set_tid_address,	"set_tid_address"}, /* 218 */
+	{ 0,	0,	sys_restart_syscall,	"restart_syscall"}, /* 219 */
+	{ 5,	TI,	sys_semtimedop,		"semtimedop"	}, /* 220 */
+	{ 4,	TD,	sys_fadvise64_64,	"fadvise64"	}, /* 221 */
+	{ },							   /* 222 */
+	{ 4,	0,	sys_timer_settime,	"timer_settime"	}, /* 223 */
+	{ 2,	0,	sys_timer_gettime,	"timer_gettime"	}, /* 224 */
+	{ 1,	0,	sys_timer_getoverrun,	"timer_getoverrun"}, /* 225 */
+	{ 1,	0,	sys_timer_delete,	"timer_delete"	}, /* 226 */
+	{ 2,	0,	sys_clock_settime,	"clock_settime"	}, /* 227 */
+	{ 2,	0,	sys_clock_gettime,	"clock_gettime"	}, /* 228 */
+	{ 2,	0,	sys_clock_getres,	"clock_getres"	}, /* 229 */
+	{ 4,	0,	sys_clock_nanosleep,	"clock_nanosleep"}, /* 230 */
+	{ 1,	TP,	sys_exit,		"exit_group"	}, /* 231 */
+	{ 4,	TD,	sys_epoll_wait,		"epoll_wait"	}, /* 232 */
+	{ 4,	TD,	sys_epoll_ctl,		"epoll_ctl"	}, /* 233 */
+	{ 3,	TS,	sys_tgkill,		"tgkill"	}, /* 234 */
+	{ 2,	TF,	sys_utimes,		"utimes"	}, /* 235 */
+	{ },							   /* 236 */
+	{ 6,	0,	sys_mbind,		"mbind"		}, /* 237 */
+	{ 3,	0,	sys_set_mempolicy,	"set_mempolicy"	}, /* 238 */
+	{ 5,	0,	sys_get_mempolicy,	"get_mempolicy"	}, /* 239 */
+	{ 4,	0,	sys_mq_open,		"mq_open"	}, /* 240 */
+	{ 1,	0,	sys_mq_unlink,		"mq_unlink"	}, /* 241 */
+	{ 5,	0,	sys_mq_timedsend,	"mq_timedsend"	}, /* 242 */
+	{ 5,	0,	sys_mq_timedreceive,	"mq_timedreceive" }, /* 243 */
+	{ },							   /* 244 */
+	{ 3,	0,	sys_mq_getsetattr,	"mq_getsetattr"	}, /* 245 */
+	{ },							   /* 246 */
+	{ },							   /* 247 */
+	{ 5,	0,	sys_add_key,		"add_key"	}, /* 248 */
+	{ 4,	0,	sys_request_key,	"request_key"	}, /* 249 */
+	{ 5,	0,	sys_keyctl,		"keyctl"	}, /* 250 */
+	{ 3,	0,	sys_ioprio_set,		"ioprio_set"	}, /* 251 */
+	{ 2,	0,	sys_ioprio_get,		"ioprio_get"	}, /* 252 */
+	{ 0,	TD,	sys_inotify_init,	"inotify_init"	}, /* 253 */
+	{ 3,	TD,	sys_inotify_add_watch,	"inotify_add_watch" }, /* 254 */
+	{ 2,	TD,	sys_inotify_rm_watch,	"inotify_rm_watch" }, /* 255 */
+	{ 4,	0,	sys_migrate_pages,	"migrate_pages"	}, /* 256 */
+	{ 4,	TD|TF,	sys_openat,		"openat"	}, /* 257 */
+	{ 3,	TD|TF,	sys_mkdirat,		"mkdirat"	}, /* 258 */
+	{ 4,	TD|TF,	sys_mknodat,		"mknodat"	}, /* 259 */
+	{ 5,	TD|TF,	sys_fchownat,		"fchownat"	}, /* 260 */
+	{ 3,	TD|TF,	sys_futimesat,		"futimesat"	}, /* 261 */
+	{ 4,	TD|TF,	sys_newfstatat,		"newfstatat"	}, /* 262 */
+	{ 3,	TD|TF,	sys_unlinkat,		"unlinkat"	}, /* 263 */
+	{ 4,	TD|TF,	sys_renameat,		"renameat"	}, /* 264 */
+	{ 5,	TD|TF,	sys_linkat,		"linkat"	}, /* 265 */
+	{ 3,	TD|TF,	sys_symlinkat,		"symlinkat"	}, /* 266 */
+	{ 4,	TD|TF,	sys_readlinkat,		"readlinkat"	}, /* 267 */
+	{ 3,	TD|TF,	sys_fchmodat,		"fchmodat"	}, /* 268 */
+	{ 3,	TD|TF,	sys_faccessat,		"faccessat"	}, /* 269 */
+	{ 6,	TD,	sys_pselect6,		"pselect6"	}, /* 270 */
+	{ 5,	TD,	sys_ppoll,		"ppoll"		}, /* 271 */
+	{ 1,	TP,	sys_unshare,		"unshare"	}, /* 272 */
+	{ },							   /* 273 */
+	{ },							   /* 274 */
+	{ 6,	TD,	sys_splice,		"splice"	}, /* 275 */
+	{ 4,	TD,	sys_tee,		"tee"		}, /* 276 */
+	{ 4,	TD,	sys_sync_file_range,	"sync_file_range" }, /* 277 */
+	{ },							   /* 278 */
+	{ },							   /* 279 */
+	{ 4,	TD|TF,	sys_utimensat,		"utimensat"	}, /* 280 */
+	{ 6,	TD,	sys_epoll_pwait,	"epoll_pwait"	}, /* 281 */
+	{ 3,	TD|TS,	sys_signalfd,		"signalfd"	}, /* 282 */
+	{ 2,	TD,	sys_timerfd_create,	"timerfd_create"}, /* 283 */
+	{ 1,	TD,	sys_eventfd,		"eventfd"	}, /* 284 */
+	{ 6,	TD,	sys_fallocate,		"fallocate"	}, /* 285 */
+	{ 4,	TD,	sys_timerfd_settime,	"timerfd_settime"}, /* 286 */
+	{ 2,	TD,	sys_timerfd_gettime,	"timerfd_gettime"}, /* 287 */
+	{ 4,	TN,	sys_accept4,		"accept4"	}, /* 288 */
+	{ 4,	TD|TS,	sys_signalfd4,		"signalfd4"	}, /* 289 */
+	{ 2,	TD,	sys_eventfd2,		"eventfd2"	}, /* 290 */
+	{ 1,	TD,	sys_epoll_create1,	"epoll_create1"	}, /* 291 */
+	{ 3,	TD,	sys_dup3,		"dup3"		}, /* 292 */
+	{ 2,	TD,	sys_pipe2,		"pipe2"		}, /* 293 */
+	{ 1,	TD,	sys_inotify_init1,	"inotify_init1"	}, /* 294 */
+	{ },							   /* 295 */
+	{ },							   /* 296 */
+	{ },							   /* 297 */
+	{ 5,	TD,	sys_perf_event_open,	"perf_event_open"}, /* 298 */
+	{ },							   /* 299 */
+	{ 2,	TD,	sys_fanotify_init,	"fanotify_init"	}, /* 300 */
+	{ 5,	TD|TF,	sys_fanotify_mark,	"fanotify_mark"	}, /* 301 */
+	{ 4,	0,	sys_prlimit64,		"prlimit64"	}, /* 302 */
+	{ 5,	TD|TF,	sys_name_to_handle_at,	"name_to_handle_at"}, /* 303 */
+	{ 3,	TD,	sys_open_by_handle_at,	"open_by_handle_at"}, /* 304 */
+	{ 2,	0,	sys_clock_adjtime,	"clock_adjtime"	}, /* 305 */
+	{ 1,	TD,	sys_syncfs,		"syncfs"	}, /* 306 */
+	{ },							   /* 307 */
+	{ 2,	TD,	sys_setns,		"setns"		}, /* 308 */
+	{ 3,	0,	sys_getcpu,		"getcpu"	}, /* 309 */
+	{ },							   /* 310 */
+	{ },							   /* 311 */
+
+	[312 ... 511] = {},
+
+	{ 4,	TS,	sys_rt_sigaction,	"rt_sigaction"	},  /* 512 */
+	{ 0,	TS,	sys_rt_sigreturn,	"rt_sigreturn"	},  /* 513 */
+	{ 3,	TD,	sys_ioctl,		"ioctl"		},  /* 514 */
+	{ 3,	TD,	sys_readv,		"readv"		},  /* 515 */
+	{ 3,	TD,	sys_writev,		"writev"	},  /* 516 */
+	{ 6,	TN,	sys_recvfrom,		"recvfrom"	},  /* 517 */
+	{ 3,	TN,	sys_sendmsg,		"sendmsg"	},  /* 518 */
+	{ 5,	TN,	sys_recvmsg,		"recvmsg"	},  /* 519 */
+	{ 3,	TF|TP,	sys_execve,		"execve"	},  /* 520 */
+	{ 4,	0,	sys_ptrace,		"ptrace"	},  /* 521 */
+	{ 2,	TS,	sys_rt_sigpending,	"rt_sigpending"	},  /* 522 */
+	{ 4,	TS,	sys_rt_sigtimedwait,	"rt_sigtimedwait" },  /* 523 */
+	{ 3,	TS,	sys_rt_sigqueueinfo,    "rt_sigqueueinfo" },  /* 524 */
+	{ 2,	TS,	sys_sigaltstack,	"sigaltstack"	},  /* 525 */
+	{ 3,	0,	sys_timer_create,	"timer_create"	}, /* 526 */
+	{ 2,	0,	sys_mq_notify,		"mq_notify"	}, /* 527 */
+	{ 4,	0,	sys_kexec_load,		"kexec_load"	}, /* 528 */
+	{ 5,	TP,	sys_waitid,		"waitid"	}, /* 529 */
+	{ 2,	0,	sys_set_robust_list,	"set_robust_list" }, /* 530 */
+	{ 3,	0,	sys_get_robust_list,	"get_robust_list" }, /* 531 */
+	{ 4,	TD,	sys_vmsplice,		"vmsplice"	}, /* 532 */
+	{ 6,	0,	sys_move_pages,		"move_pages"	}, /* 533 */
+	{ 5,	TD,	sys_preadv,		"preadv"	}, /* 534 */
+	{ 5,	TD,	sys_pwritev,		"pwritev"	}, /* 535 */
+	{ 4,	TP|TS,	sys_rt_tgsigqueueinfo,	"rt_tgsigqueueinfo"}, /* 536 */
+	{ 5,	TN,	sys_recvmmsg,		"recvmmsg"	}, /* 537 */
+	{ 4,	TN,	sys_sendmmsg,		"sendmmsg"	}, /* 538 */
+	{ 6,	0,	sys_process_vm_readv,	"process_vm_readv"}, /* 539 */
+	{ 6,	0,	sys_process_vm_writev,	"process_vm_writev"}, /* 540 */
diff --git a/linux/x86_64/errnoent2.h b/linux/x86_64/errnoent2.h
new file mode 100644
index 0000000..00de57b
--- /dev/null
+++ b/linux/x86_64/errnoent2.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "../errnoent.h"
diff --git a/linux/x86_64/ioctlent2.h b/linux/x86_64/ioctlent2.h
new file mode 100644
index 0000000..060003b
--- /dev/null
+++ b/linux/x86_64/ioctlent2.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "linux/ioctlent.h"
diff --git a/linux/x86_64/signalent2.h b/linux/x86_64/signalent2.h
new file mode 100644
index 0000000..6fbcab1
--- /dev/null
+++ b/linux/x86_64/signalent2.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "../signalent.h"
diff --git a/linux/x86_64/syscallent2.h b/linux/x86_64/syscallent2.h
new file mode 100644
index 0000000..1d35f53
--- /dev/null
+++ b/linux/x86_64/syscallent2.h
@@ -0,0 +1,2 @@
+/* Our third set is for x32.  */
+#include "x32/syscallent.h"
diff --git a/mem.c b/mem.c
index 72b30de..8e34f96 100644
--- a/mem.c
+++ b/mem.c
@@ -320,7 +320,7 @@ int
 sys_mmap64(struct tcb *tcp)
 {
 	if (entering(tcp)) {
-#if defined(ALPHA)
+#if defined(ALPHA) || defined(X32)
 		long *u_arg = tcp->u_arg;
 #else
 		long u_arg[7];
@@ -349,7 +349,7 @@ sys_mmap64(struct tcb *tcp)
 		tprints(", ");
 		printfd(tcp, u_arg[4]);
 		/* offset */
-#if defined(ALPHA)
+#if defined(ALPHA) || defined(X32)
 		printllval(tcp, ", %#llx", 5);
 #else
 		/* NOTE: not verified that [5] and [6] should be used.
diff --git a/pathtrace.c b/pathtrace.c
index 87d9827..886932c 100644
--- a/pathtrace.c
+++ b/pathtrace.c
@@ -223,7 +223,11 @@ pathtrace_match(struct tcb *tcp)
 			upathmatch(tcp, tcp->u_arg[3]);
 	}
 
-	if (s->sys_func == sys_old_mmap || s->sys_func == sys_mmap) {
+	if (
+#if !defined X32
+	    s->sys_func == sys_old_mmap ||
+#endif
+	    s->sys_func == sys_mmap) {
 		/* x, x, x, x, fd */
 		return fdmatch(tcp, tcp->u_arg[4]);
 	}
diff --git a/process.c b/process.c
index 100ccd4..2fb6c92 100644
--- a/process.c
+++ b/process.c
@@ -465,7 +465,7 @@ extern void print_ldt_entry();
 # define ARG_PTID	2
 # define ARG_CTID	3
 # define ARG_TLS	4
-#elif defined X86_64 || defined ALPHA
+#elif defined X86_64 || defined X32 || defined ALPHA
 # define ARG_FLAGS	0
 # define ARG_STACK	1
 # define ARG_PTID	2
@@ -1589,7 +1589,7 @@ const struct xlat struct_user_offsets[] = {
 	{ 4*EFL,		"4*EFL"					},
 	{ 4*UESP,		"4*UESP"				},
 	{ 4*SS,			"4*SS"					},
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 	{ 8*R15,		"8*R15"					},
 	{ 8*R14,		"8*R14"					},
 	{ 8*R13,		"8*R13"					},
@@ -2124,7 +2124,7 @@ const struct xlat struct_user_offsets[] = {
 # if !defined(S390) && !defined(S390X) && !defined(MIPS) && !defined(SPARC64) && !defined(AVR32) && !defined(BFIN) && !defined(TILE)
 	{ uoff(u_fpvalid),	"offsetof(struct user, u_fpvalid)"	},
 # endif
-# if defined(I386) || defined(X86_64)
+# if defined(I386) || defined(X86_64) || defined(X32)
 	{ uoff(i387),		"offsetof(struct user, i387)"		},
 # endif
 # if defined(M68K)
@@ -2154,7 +2154,7 @@ const struct xlat struct_user_offsets[] = {
 # endif
 	{ uoff(magic),		"offsetof(struct user, magic)"		},
 	{ uoff(u_comm),		"offsetof(struct user, u_comm)"		},
-# if defined(I386) || defined(X86_64)
+# if defined(I386) || defined(X86_64) || defined(X32)
 	{ uoff(u_debugreg),	"offsetof(struct user, u_debugreg)"	},
 # endif
 #endif /* !defined(many arches) */
@@ -2566,7 +2566,7 @@ sys_sched_rr_get_interval(struct tcb *tcp)
 	return 0;
 }
 
-#ifdef X86_64
+#if defined X86_64 || defined X32
 # include <asm/prctl.h>
 
 static const struct xlat archvals[] = {
@@ -2600,7 +2600,7 @@ sys_arch_prctl(struct tcb *tcp)
 	}
 	return 0;
 }
-#endif /* X86_64 */
+#endif /* X86_64 || X32 */
 
 int
 sys_getcpu(struct tcb *tcp)
diff --git a/resource.c b/resource.c
index d7a34ef..8464071 100644
--- a/resource.c
+++ b/resource.c
@@ -428,9 +428,11 @@ sys_times(struct tcb *tcp)
 			tprints("{...}");
 		else {
 			tprintf("{tms_utime=%lu, tms_stime=%lu, ",
-				tbuf.tms_utime, tbuf.tms_stime);
+				(unsigned long) tbuf.tms_utime,
+				(unsigned long) tbuf.tms_stime);
 			tprintf("tms_cutime=%lu, tms_cstime=%lu}",
-				tbuf.tms_cutime, tbuf.tms_cstime);
+				(unsigned long) tbuf.tms_cutime,
+				(unsigned long) tbuf.tms_cstime);
 		}
 	}
 	return 0;
diff --git a/signal.c b/signal.c
index ab7ae56..17be957 100644
--- a/signal.c
+++ b/signal.c
@@ -73,7 +73,7 @@ typedef struct {
 	int			si_mask;
 } m_siginfo_t;
 #elif defined HAVE_ASM_SIGCONTEXT_H
-# if !defined(IA64) && !defined(X86_64)
+# if !defined(IA64) && !defined(X86_64) && !defined(X32)
 #  include <asm/sigcontext.h>
 # endif
 #else /* !HAVE_ASM_SIGCONTEXT_H */
@@ -132,7 +132,7 @@ struct sigcontext
 
 #ifdef HAVE_SIGACTION
 
-#if defined(I386) || defined(X86_64)
+#if defined I386 || defined X86_64 || defined X32
 /* The libc headers do not define this constant since it should only be
    used by the implementation.  So we define it here.  */
 # ifndef SA_RESTORER
@@ -723,8 +723,8 @@ printsiginfo(siginfo_t *sip, int verbose)
 					tprints(", ...");
 				else
 					tprintf(", si_utime=%lu, si_stime=%lu",
-						sip->si_utime,
-						sip->si_stime);
+						(unsigned long) sip->si_utime,
+						(unsigned long) sip->si_stime);
 				break;
 			case SIGILL: case SIGFPE:
 			case SIGSEGV: case SIGBUS:
diff --git a/syscall.c b/syscall.c
index ddc461c..0fdc1bd 100644
--- a/syscall.c
+++ b/syscall.c
@@ -261,12 +261,18 @@ update_personality(struct tcb *tcp, int personality)
 		return;
 	tcp->currpers = personality;
 
-# if defined(POWERPC64) || defined(X86_64)
+# if defined(POWERPC64)
 	if (!qflag) {
 		static const char *const names[] = {"64 bit", "32 bit"};
 		fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
 			tcp->pid, names[personality]);
 	}
+# elif defined(X86_64)
+	if (!qflag) {
+		static const char *const names[] = {"64 bit", "32 bit", "x32"};
+		fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
+			tcp->pid, names[personality]);
+	}
 # endif
 }
 #endif
@@ -622,7 +628,7 @@ is_restart_error(struct tcb *tcp)
 
 #if defined(I386)
 struct pt_regs i386_regs;
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 /*
  * On 32 bits, pt_regs and user_regs_struct are the same,
  * but on 64 bits, user_regs_struct has six more fields:
@@ -795,7 +801,14 @@ get_scno(struct tcb *tcp)
 	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
 		return -1;
 	scno = i386_regs.orig_eax;
-#elif defined(X86_64)
+#elif defined (X86_64) || defined(X32)
+# ifndef __X32_SYSCALL_BIT
+#  define __X32_SYSCALL_BIT	0x40000000
+# endif
+# ifndef __X32_SYSCALL_MASK
+#  define __X32_SYSCALL_MASK	__X32_SYSCALL_BIT
+# endif
+
 	int currpers;
 	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
 		return -1;
@@ -804,10 +817,18 @@ get_scno(struct tcb *tcp)
 	/* Check CS register value. On x86-64 linux it is:
 	 *	0x33	for long mode (64 bit)
 	 *	0x23	for compatibility mode (32 bit)
+	 * Check DS register value. On x86-64 linux it is:
+	 *	0x2b	for x32 mode (x86-64 in 32 bit)
 	 */
 	switch (x86_64_regs.cs) {
 		case 0x23: currpers = 1; break;
-		case 0x33: currpers = 0; break;
+		case 0x33:
+			if (x86_64_regs.ds == 0x2b) {
+				currpers = 2;
+				scno &= ~__X32_SYSCALL_MASK;
+			} else
+				currpers = 0;
+			break;
 		default:
 			fprintf(stderr, "Unknown value CS=0x%08X while "
 				 "detecting personality of process "
@@ -846,7 +867,16 @@ get_scno(struct tcb *tcp)
 			break;
 	}
 # endif
+# ifdef X32
+	if (currpers == 0 || currpers == 1) {
+		fprintf(stderr, "syscall_%lu (...) in unsupported %s "
+			"mode of process PID=%d\n", scno,
+			currpers == 0 ? "64-bit" : "32-bit", tcp->pid);
+		return 0;
+	}
+# else
 	update_personality(tcp, currpers);
+# endif
 #elif defined(IA64)
 #	define IA64_PSR_IS	((long)1 << 34)
 	if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
@@ -1096,7 +1126,7 @@ syscall_fixup_on_sysenter(struct tcb *tcp)
 			fprintf(stderr, "not a syscall entry (eax = %ld)\n", i386_regs.eax);
 		return 0;
 	}
-#elif defined(X86_64)
+#elif defined (X86_64) || defined (X32)
 	{
 		long rax = x86_64_regs.rax;
 		if (current_personality == 1)
@@ -1385,16 +1415,24 @@ get_syscall_args(struct tcb *tcp)
 	for (i = 0; i < nargs; ++i)
 		if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0)
 			return -1;
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 	(void)i;
 	(void)nargs;
-	if (current_personality == 0) { /* x86-64 ABI */
+	if (current_personality != 1) { /* x86-64 or x32 ABI */
 		tcp->u_arg[0] = x86_64_regs.rdi;
 		tcp->u_arg[1] = x86_64_regs.rsi;
 		tcp->u_arg[2] = x86_64_regs.rdx;
 		tcp->u_arg[3] = x86_64_regs.r10;
 		tcp->u_arg[4] = x86_64_regs.r8;
 		tcp->u_arg[5] = x86_64_regs.r9;
+#  ifdef X32
+		tcp->ext_arg[0] = x86_64_regs.rdi;
+		tcp->ext_arg[1] = x86_64_regs.rsi;
+		tcp->ext_arg[2] = x86_64_regs.rdx;
+		tcp->ext_arg[3] = x86_64_regs.r10;
+		tcp->ext_arg[4] = x86_64_regs.r8;
+		tcp->ext_arg[5] = x86_64_regs.r9;
+#  endif
 	} else { /* i386 ABI */
 		/* Sign-extend lower 32 bits */
 		tcp->u_arg[0] = (long)(int)x86_64_regs.rbx;
@@ -1569,7 +1607,7 @@ get_syscall_result(struct tcb *tcp)
 #elif defined(I386)
 	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &i386_regs) < 0)
 		return -1;
-#elif defined(X86_64)
+#elif defined (X86_64) || defined (X32)
 	if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long) &x86_64_regs) < 0)
 		return -1;
 #elif defined(IA64)
@@ -1701,13 +1739,16 @@ get_error(struct tcb *tcp)
 	else {
 		tcp->u_rval = i386_regs.eax;
 	}
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 	if (check_errno && is_negated_errno(x86_64_regs.rax)) {
 		tcp->u_rval = -1;
 		u_error = -x86_64_regs.rax;
 	}
 	else {
 		tcp->u_rval = x86_64_regs.rax;
+# if defined(X32)
+		tcp->u_lrval = x86_64_regs.rax;
+# endif
 	}
 #elif defined(IA64)
 	if (ia32) {
@@ -1735,6 +1776,9 @@ get_error(struct tcb *tcp)
 		u_error = r2;
 	} else {
 		tcp->u_rval = r2;
+# if defined(LINUX_MIPSN32)
+		tcp->u_lrval = r2;
+# endif
 	}
 #elif defined(POWERPC)
 	if (check_errno && is_negated_errno(ppc_result)) {
@@ -2065,6 +2109,20 @@ trace_syscall_exiting(struct tcb *tcp)
 			case RVAL_DECIMAL:
 				tprintf("= %ld", tcp->u_rval);
 				break;
+#ifdef HAVE_LONG_LONG
+			case RVAL_LHEX:
+				tprintf("= %#llx", tcp->u_lrval);
+				break;
+			case RVAL_LOCTAL:
+				tprintf("= %#llo", tcp->u_lrval);
+				break;
+			case RVAL_LUDECIMAL:
+				tprintf("= %llu", tcp->u_lrval);
+				break;
+			case RVAL_LDECIMAL:
+				tprintf("= %lld", tcp->u_lrval);
+				break;
+#endif
 			default:
 				fprintf(stderr,
 					"invalid rval format\n");
diff --git a/util.c b/util.c
index 348d77f..edba2cb 100644
--- a/util.c
+++ b/util.c
@@ -212,7 +212,7 @@ printllval(struct tcb *tcp, const char *format, int llarg)
 # elif defined IA64 || defined ALPHA
 	tprintf(format, tcp->u_arg[llarg]);
 	llarg++;
-# elif defined LINUX_MIPSN32
+# elif defined LINUX_MIPSN32 || defined X32
 	tprintf(format, tcp->ext_arg[llarg]);
 	llarg++;
 # else
@@ -997,7 +997,7 @@ printcall(struct tcb *tcp)
 	tprintf("[%16lx] ", psw);
 # endif
 
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 	long rip;
 
 	if (upeek(tcp, 8*RIP, &rip) < 0) {
@@ -1151,7 +1151,7 @@ change_syscall(struct tcb *tcp, int new)
 	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
 		return -1;
 	return 0;
-#elif defined(X86_64)
+#elif defined(X86_64) || defined(X32)
 	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
 		return -1;
 	return 0;
@@ -1392,7 +1392,7 @@ typedef struct pt_regs arg_setup_state;
 # elif defined(HPPA)
 #  define arg0_offset	PT_GR26
 #  define arg1_offset	(PT_GR26-4)
-# elif defined(X86_64)
+# elif defined (X86_64) || defined(X32)
 #  define arg0_offset	((long)(8*(current_personality ? RBX : RDI)))
 #  define arg1_offset	((long)(8*(current_personality ? RCX : RSI)))
 # elif defined(SH)




More information about the Strace-devel mailing list