Fix decoding of getgroups, getgroups32, setgroups, and setgroups32 syscalls

Convert parsers of these syscalls to the same scheme as were applied to
parsers of other uid/gid related syscalls.
That is, define two sets of parsers on architectures that support
(either directly or via multiarch) 16-bit and 32-bit gid getgroups
and setgroups syscalls simultaneously, and reuse essentially the same
code by parametrizing uid_t and names of parser functions.

* groups.c: Remove.
(sys_getgroups, sys_setgroups): Move ...
* uid.c: ... here and parametrize their names.
* Makefile.am (strace_SOURCES): Remove groups.c.
* linux/syscall.h (sys_getgroups32, sys_setgroups32): Remove.
[NEED_UID16_PARSERS] (sys_getgroups16, sys_setgroups16): New prototypes.
* linux/arm/syscallent.h: Rename sys_[gs]etgroups to sys_[gs]etgroups16,
rename sys_[gs]etgroups32 to sys_[gs]etgroups.
* linux/bfin/syscallent.h: Likewise.
* linux/i386/syscallent.h: Likewise.
* linux/m68k/syscallent.h: Likewise.
* linux/microblaze/syscallent.h: Likewise.
* linux/s390/syscallent.h: Likewise.
* linux/sh/syscallent.h: Likewise.
* linux/sh64/syscallent.h: Likewise.
* linux/sparc/syscallent.h: Likewise.
* tests/uid.c: Test for getgroups.
* tests/uid16.c: Likewise.
* tests/uid32.c: Test for getgroups32.
* tests/uid.awk: Test for getgroups/getgroups32 decoding.
* tests/uid.test: Trace getgroups/getgroups32 syscalls.
diff --git a/uid.c b/uid.c
index 376d059..1f8c365 100644
--- a/uid.c
+++ b/uid.c
@@ -7,15 +7,17 @@
 # define SIZEIFY_(x,size)	SIZEIFY__(x,size)
 # define SIZEIFY__(x,size)	x ## size
 
-# define sys_getuid	SIZEIFY(sys_getuid)
-# define sys_setfsuid	SIZEIFY(sys_setfsuid)
-# define sys_setuid	SIZEIFY(sys_setuid)
-# define sys_getresuid	SIZEIFY(sys_getresuid)
-# define sys_setreuid	SIZEIFY(sys_setreuid)
-# define sys_setresuid	SIZEIFY(sys_setresuid)
+# define printuid	SIZEIFY(printuid)
 # define sys_chown	SIZEIFY(sys_chown)
 # define sys_fchown	SIZEIFY(sys_fchown)
-# define printuid	SIZEIFY(printuid)
+# define sys_getgroups	SIZEIFY(sys_getgroups)
+# define sys_getresuid	SIZEIFY(sys_getresuid)
+# define sys_getuid	SIZEIFY(sys_getuid)
+# define sys_setfsuid	SIZEIFY(sys_setfsuid)
+# define sys_setgroups	SIZEIFY(sys_setgroups)
+# define sys_setresuid	SIZEIFY(sys_setresuid)
+# define sys_setreuid	SIZEIFY(sys_setreuid)
+# define sys_setuid	SIZEIFY(sys_setuid)
 #endif /* STRACE_UID_SIZE */
 
 #include "defs.h"
@@ -141,4 +143,117 @@
 		tprintf("%s%u", text, uid);
 }
 
+int
+sys_setgroups(struct tcb *tcp)
+{
+	if (entering(tcp)) {
+		unsigned long len, size, start, cur, end, abbrev_end;
+		uid_t gid;
+		int failed = 0;
+
+		len = tcp->u_arg[0];
+		tprintf("%lu, ", len);
+		if (len == 0) {
+			tprints("[]");
+			return 0;
+		}
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprints("NULL");
+			return 0;
+		}
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprints("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprints(", ");
+			if (cur >= abbrev_end) {
+				tprints("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprints("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%u", (unsigned int) gid);
+		}
+		tprints("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
+	}
+	return 0;
+}
+
+int
+sys_getgroups(struct tcb *tcp)
+{
+	unsigned long len;
+
+	if (entering(tcp)) {
+		len = tcp->u_arg[0];
+		tprintf("%lu, ", len);
+	} else {
+		unsigned long size, start, cur, end, abbrev_end;
+		uid_t gid;
+		int failed = 0;
+
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprints("NULL");
+			return 0;
+		}
+		len = tcp->u_rval;
+		if (len == 0) {
+			tprints("[]");
+			return 0;
+		}
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+		    size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprints("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprints(", ");
+			if (cur >= abbrev_end) {
+				tprints("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprints("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%u", (unsigned int) gid);
+		}
+		tprints("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
+	}
+	return 0;
+}
+
 #endif /* STRACE_UID_SIZE */