From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:60174) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qp6D8-0004xL-Ff for qemu-devel@nongnu.org; Thu, 04 Aug 2011 18:16:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Qp6D7-0006Lv-B2 for qemu-devel@nongnu.org; Thu, 04 Aug 2011 18:16:14 -0400 Received: from na3sys009aog104.obsmtp.com ([74.125.149.73]:38104) by eggs.gnu.org with smtp (Exim 4.71) (envelope-from ) id 1Qp6D6-0006Ln-Kv for qemu-devel@nongnu.org; Thu, 04 Aug 2011 18:16:13 -0400 Received: by mail-iy0-f169.google.com with SMTP id 1so1811596iym.14 for ; Thu, 04 Aug 2011 15:16:06 -0700 (PDT) Date: Thu, 4 Aug 2011 15:16:00 -0700 From: An-Cheng Huang Message-ID: <20110804221600.GA5323@debian.localdomain> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Subject: [Qemu-devel] [PATCH] linux-user: Fix indirect syscall handling for MIPS List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: riku.voipio@iki.fi I ran into the problem of indirect syscalls not working with mips-linux-user and found that the number of arguments for sys_syscall is 0 in the mips_syscall_args table, which means the "higher" arguments (5, 6, 7, and 8) are never obtained from the stack for the do_syscall() invocation for indirect syscalls. So the actual syscall will not get the correct argument(s) if it needs more than three. The patch checks for indirect syscall and in such cases uses the actual syscall number to look up the number of arguments so that the actual arguments can be taken from the stack. A simpler approach would be to just change the number of arguments for sys_syscall to 8 in the mips_syscall_args table so that for indirect syscalls the "higher" arguments are always taken from the stack with get_user_ual(). However, since there is a comment about "what to do if get_user() fails", I don't know if this may cause breakage when the arguments are not actually there? If someone can confirm that this is harmless, the simple approach is probably better? Thanks. Signed-off-by: An-Cheng Huang --- linux-user/main.c | 21 ++++++++++++++++++--- 1 files changed, 18 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 6a8f4bd..1560c1c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2068,27 +2068,42 @@ static int do_store_exclusive(CPUMIPSState *env) void cpu_loop(CPUMIPSState *env) { target_siginfo_t info; int trapnr, ret; unsigned int syscall_num; + unsigned int syscall_idx; + unsigned int real_syscall_idx; /* only for indirect syscall */ for(;;) { cpu_exec_start(env); trapnr = cpu_mips_exec(env); cpu_exec_end(env); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->active_tc.gpr[2] - 4000; + syscall_num = env->active_tc.gpr[2]; + syscall_idx = syscall_num - 4000; + real_syscall_idx = env->active_tc.gpr[4] - 4000; env->active_tc.PC += 4; - if (syscall_num >= sizeof(mips_syscall_args)) { + if (syscall_idx >= sizeof(mips_syscall_args) + || (syscall_num == TARGET_NR_syscall + && real_syscall_idx >= sizeof(mips_syscall_args))) { + /* invalid direct or indirect syscalls */ ret = -TARGET_ENOSYS; } else { int nb_args; abi_ulong sp_reg; abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; - nb_args = mips_syscall_args[syscall_num]; + if (syscall_num == TARGET_NR_syscall) { + /* indirect syscall, so need to look at the real + * syscall to figure out nb_args. also, plus 1 is + * needed to account for the indirect syscall itself. + */ + nb_args = mips_syscall_args[real_syscall_idx] + 1; + } else { + nb_args = mips_syscall_args[syscall_idx]; + } sp_reg = env->active_tc.gpr[29]; switch (nb_args) { /* these arguments are taken from the stack */ /* FIXME - what to do if get_user() fails? */ case 8: get_user_ual(arg8, sp_reg + 28);