Fix corner cases of socketcall syscall

* xlat/socketcalls.in: New file.
* socketcall.c: New file.
* Makefile.am (libstrace_a_SOURCES): Add it.
* linux/dummy.h (sys_socketcall): Remove stub alias.
* syscall.c (decode_socket_subcall): Treat 1st argument of socketcall
as "int".  Do not substitute syscall until all socketcall arguments
have been fetched successfully.
diff --git a/Makefile.am b/Makefile.am
index ecdafbf..adddc61 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -66,6 +66,7 @@
 libstrace_a_SOURCES =	\
 	fstatfs.c \
 	fstatfs64.c \
+	socketcall.c \
 	statfs.c \
 	statfs64.c \
 	sync_file_range.c \
diff --git a/linux/dummy.h b/linux/dummy.h
index bb23f5d..cfc2c3e 100644
--- a/linux/dummy.h
+++ b/linux/dummy.h
@@ -113,7 +113,6 @@
 #define	sys_setsid		printargs
 #define	sys_set_tid_address	printargs
 #define	sys_setup		printargs
-#define	sys_socketcall		printargs
 #define	sys_sync		printargs
 #define	sys_syscall		printargs
 #define	sys_vhangup		printargs
diff --git a/socketcall.c b/socketcall.c
new file mode 100644
index 0000000..3f18821
--- /dev/null
+++ b/socketcall.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+#include "xlat/socketcalls.h"
+
+SYS_FUNC(socketcall)
+{
+	const unsigned int call = tcp->u_arg[0];
+	const char *str = xlookup(socketcalls, call);
+
+	if (str)
+		tprints(str);
+	else
+		tprintf("%d", call);
+
+	unsigned int i;
+	for (i = 1; i < MAX_ARGS; ++i)
+		tprintf(", %#lx", tcp->u_arg[i]);
+
+	return RVAL_DECODED;
+}
diff --git a/syscall.c b/syscall.c
index 5c83818..7a842cc 100644
--- a/syscall.c
+++ b/syscall.c
@@ -567,29 +567,26 @@
 static void
 decode_socket_subcall(struct tcb *tcp)
 {
-	unsigned long addr;
-	unsigned int n;
+	const int call = tcp->u_arg[0];
 
-	if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= SYS_socket_nsubcalls)
+	if (call < 1 || call >= SYS_socket_nsubcalls)
 		return;
 
-	tcp->scno = SYS_socket_subcall + tcp->u_arg[0];
-	tcp->qual_flg = qual_flags[tcp->scno];
-	tcp->s_ent = &sysent[tcp->scno];
-	addr = tcp->u_arg[1];
-	n = tcp->s_ent->nargs;
-	if (sizeof(tcp->u_arg[0]) == current_wordsize) {
-		memset(tcp->u_arg, 0, n * sizeof(tcp->u_arg[0]));
-		(void) umoven(tcp, addr, n * sizeof(tcp->u_arg[0]), tcp->u_arg);
-	} else {
-		unsigned int args[n];
-		unsigned int i;
+	const unsigned long scno = SYS_socket_subcall + call;
+	const unsigned int nargs = sysent[scno].nargs;
+	uint64_t buf[nargs];
 
-		memset(args, 0, sizeof(args));
-		(void) umove(tcp, addr, &args);
-		for (i = 0; i < n; ++i)
-			tcp->u_arg[i] = args[i];
-	}
+	if (umoven(tcp, tcp->u_arg[1], nargs * current_wordsize, buf) < 0)
+		return;
+
+	tcp->scno = scno;
+	tcp->qual_flg = qual_flags[scno];
+	tcp->s_ent = &sysent[scno];
+
+	unsigned int i;
+	for (i = 0; i < nargs; ++i)
+		tcp->u_arg[i] = (sizeof(uint32_t) == current_wordsize)
+				? ((uint32_t *) buf)[i] : buf[i];
 }
 #endif
 
diff --git a/xlat/socketcalls.in b/xlat/socketcalls.in
new file mode 100644
index 0000000..3ffeb6f
--- /dev/null
+++ b/xlat/socketcalls.in
@@ -0,0 +1,20 @@
+SYS_SOCKET	1
+SYS_BIND	2
+SYS_CONNECT	3
+SYS_LISTEN	4
+SYS_ACCEPT	5
+SYS_GETSOCKNAME	6
+SYS_GETPEERNAME	7
+SYS_SOCKETPAIR	8
+SYS_SEND	9
+SYS_RECV	10
+SYS_SENDTO	11
+SYS_RECVFROM	12
+SYS_SHUTDOWN	13
+SYS_SETSOCKOPT	14
+SYS_GETSOCKOPT	15
+SYS_SENDMSG	16
+SYS_RECVMSG	17
+SYS_ACCEPT4	18
+SYS_RECVMMSG	19
+SYS_SENDMMSG	20