2007-08-26  Daniel Jacobowitz  <dan@codesourcery.com>

	* defs.h [MIPS]: Include <sgidefs.h>.
	(MAX_QUALS): Update for MIPS.
	(LINUX_MIPSO32, LINUX_MIPSN32, LINUX_MIPSN64, LINUX_MIPS64): Define.
	(struct tcb): Add ext_arg for MIPS N32.
	(TCB_WAITEXECVE): Define for MIPS.
	(ALIGN64): Use LINUX_MIPSO32.
	* file.c (sys_lseek): Use ext_arg for MIPS N32.
	(sys_readahead, sys_fadvise64_64): Likewise.
	* io.c (sys_pread64, sys_pwrite64): Likewise.
	* mem.c (print_mmap): Take OFFSET argument.
	(sys_old_mmap): Update call to print_mmap.
	(sys_mmap): Use ext_arg for MIPS N32.
	* process.c (struct_user_offsets): Add MIPS registers.
	* signal.c (sys_sigreturn): Handle MIPS N32 and MIPS N64.  Correct
	MIPS O32 call to sprintsigmask.
	* syscall.c (internal_syscall): Handle MIPS N32.  Check for
	TCB_WAITEXECVE on MIPS.
	(force_result): Add a comment about MIPS N32.
	(syscall_enter): Handle MIPS N32 and MIPS N64.
	* linux/syscall.h (sys_pread64, sys_pwrite64): Declare.
	* linux/mips/syscallent.h: Include "dummy.h".  Handle alternate
	MIPS ABIs.
diff --git a/syscall.c b/syscall.c
index f42b121..e699c61 100644
--- a/syscall.c
+++ b/syscall.c
@@ -754,6 +754,9 @@
 #elif defined (SPARC) || defined (SPARC64)
 	static struct regs regs;
 	static unsigned long trap;
+#elif defined(LINUX_MIPSN32)
+	static long long a3;
+	static long long r2;
 #elif defined(MIPS)
 	static long a3;
 	static long r2;
@@ -1066,14 +1069,44 @@
 #elif defined (M68K)
 	if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
 		return -1;
+#elif defined (LINUX_MIPSN32)
+	unsigned long long regs[38];
+
+	if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
+		return -1;
+	a3 = regs[REG_A3];
+	r2 = regs[REG_V0];
+
+	if(!(tcp->flags & TCB_INSYSCALL)) {
+		scno = r2;
+
+		/* Check if we return from execve. */
+		if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
+			tcp->flags &= ~TCB_WAITEXECVE;
+			return 0;
+		}
+
+		if (scno < 0 || scno > nsyscalls) {
+			if(a3 == 0 || a3 == -1) {
+				if(debug)
+					fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno);
+				return 0;
+			}
+		}
+	}
 #elif defined (MIPS)
 	if (upeek(pid, REG_A3, &a3) < 0)
 	  	return -1;
-
 	if(!(tcp->flags & TCB_INSYSCALL)) {
 	  	if (upeek(pid, REG_V0, &scno) < 0)
 		  	return -1;
 
+		/* Check if we return from execve. */
+		if (scno == 0 && tcp->flags & TCB_WAITEXECVE) {
+			tcp->flags &= ~TCB_WAITEXECVE;
+			return 0;
+		}
+
 		if (scno < 0 || scno > nsyscalls) {
 			if(a3 == 0 || a3 == -1) {
 				if(debug)
@@ -1732,6 +1765,7 @@
 		r2 = rval;
 		a3 = 0;
 	}
+	/* PTRACE_POKEUSER is OK even for n32 since rval is only a long.  */
 	if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), a3) < 0 ||
 	    ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), r2) < 0)
 	    	return -1;
@@ -1957,6 +1991,27 @@
 				tcp->u_nargs = 5;
 		}
 	}
+#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64)
+	/* N32 and N64 both use up to six registers.  */
+	{
+		unsigned long long regs[38];
+	  	int i, nargs;
+
+		if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+			nargs = tcp->u_nargs = sysent[tcp->scno].nargs;
+		else 
+     	        	nargs = tcp->u_nargs = MAX_ARGS;
+
+		if (ptrace (PTRACE_GETREGS, pid, NULL, (long) &regs) < 0)
+			return -1;
+
+		for(i = 0; i < nargs; i++) {
+			tcp->u_arg[i] = regs[REG_A0 + i];
+# if defined (LINUX_MIPSN32)
+			tcp->ext_arg[i] = regs[REG_A0 + i];
+# endif
+		}
+	}
 #elif defined (MIPS)
 	{
 	  	long sp;