qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] linux-user: Fix indirect syscall handling for MIPS


From: An-Cheng Huang
Subject: [Qemu-devel] [PATCH] linux-user: Fix indirect syscall handling for MIPS
Date: Thu, 4 Aug 2011 15:16:00 -0700
User-agent: Mutt/1.5.20 (2009-06-14)

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 <address@hidden>
---
 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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]