]> git.eshelyaron.com Git - emacs.git/commitdiff
Update Android port
authorPo Lu <luangruo@yahoo.com>
Thu, 4 May 2023 01:12:26 +0000 (09:12 +0800)
committerPo Lu <luangruo@yahoo.com>
Thu, 4 May 2023 01:12:26 +0000 (09:12 +0800)
* exec/trace.c (check_signal): New function.
(handle_exec, process_system_call): Handle signal-delivery-stop
while waiting synchronously for syscall completion.

exec/trace.c

index 579a62f6c5e5e29424af90023ff5b4e14bc6935a..f9dd4d419f48c4a3dbddb3a575891934111b8a63 100644 (file)
@@ -451,6 +451,8 @@ handle_clone (pid_t pid)
 /* File name of the loader binary.  */
 static const char *loader_name;
 
+\f
+
 /* Return whether or not the trap signal described by SIGNAL is
    generated by a system call being attempted by a tracee.  */
 
@@ -463,6 +465,79 @@ syscall_trap_p (siginfo_t *signal)
          || signal->si_code == (SIGTRAP | SI_KERNEL));
 }
 
+/* Check if the wait status STATUS indicates a system call trap.
+   TRACEE is the process whose stop STATUS describes.  If TRACEE exits
+   while this information is being determined, return -1; if STATUS
+   indicates some other kind of stop, return 1 after continuing
+   TRACEE.  Value is 0 otherwise.  */
+
+static int
+check_signal (struct exec_tracee *tracee, int status)
+{
+  siginfo_t siginfo;
+
+  switch ((status & 0xfff00) >> 8)
+    {
+    case SIGTRAP:
+      /* Now, use PTRACE_GETSIGINFO to determine whether or not the
+        signal was delivered in response to a system call.  */
+
+      if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo))
+       return -1;
+
+      if (!syscall_trap_p (&siginfo))
+       {
+         if (siginfo.si_code < 0)
+           /* SIGTRAP delivered from userspace.  Pass it on.  */
+           ptrace (PTRACE_SYSCALL, tracee->pid, 0, SIGTRAP);
+         else
+           ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0);
+
+         return 1;
+       }
+
+    case SIGTRAP | 0x80: /* SIGTRAP | 0x80 specifically refers to
+                           system call traps.  */
+      break;
+
+#ifdef SIGSYS
+    case SIGSYS:
+      if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo))
+       return -1;
+
+      /* Continue the process until the next syscall, but don't
+        pass through the signal if an emulated syscall led to
+        it.  */
+#ifdef HAVE_SIGINFO_T_SI_SYSCALL
+#ifndef __arm__
+      ptrace (PTRACE_SYSCALL, tracee->pid,
+             0, ((siginfo.si_code == SYS_SECCOMP
+                  && siginfo.si_syscall == -1)
+                 ? 0 : status));
+#else /* __arm__ */
+      ptrace (PTRACE_SYSCALL, tracee->pid,
+             0, ((siginfo.si_code == SYS_SECCOMP
+                  && siginfo.si_syscall == 222)
+                 ? 0 : status));
+#endif /* !__arm__ */
+#else /* !HAVE_SIGINFO_T_SI_SYSCALL */
+      /* Drop this signal, since what caused it is unknown.  */
+      ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0);
+#endif /* HAVE_SIGINFO_T_SI_SYSCALL */
+      return 1;
+#endif /* SIGSYS */
+
+    default:
+      /* Continue the process until the next syscall.  */
+      ptrace (PTRACE_SYSCALL, tracee->pid, 0, status);
+      return 1;
+    }
+
+  return 0;
+}
+
+\f
+
 /* Handle an `exec' system call from the given TRACEE.  REGS are the
    tracee's current user-mode registers.
 
@@ -591,6 +666,15 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
     return 2;
   else
     {
+      /* Then, check if STATUS is not a syscall-stop, and try again if
+        it isn't.  */
+      rc = check_signal (tracee, wstatus);
+
+      if (rc == -1)
+       return 2;
+      else if (rc)
+       goto again;
+
       /* Retrieve the signal information and determine whether or not
         the system call has completed.  */
 
@@ -777,9 +861,6 @@ process_system_call (struct exec_tracee *tracee)
   USER_REGS_STRUCT regs;
   int rc, wstatus, save_errno;
   USER_WORD callno, sp;
-#ifdef __aarch64__
-  USER_WORD old_w1, old_w2;
-#endif /* __aarch64__ */
   USER_WORD result;
   bool reporting_error;
 
@@ -876,19 +957,7 @@ process_system_call (struct exec_tracee *tracee)
   /* First, save errno; system calls below will clobber it.  */
   save_errno = errno;
 
-#ifndef __aarch64__
   regs.SYSCALL_NUM_REG = -1;
-#else /* __aarch64__ */
-  /* ARM also requires the system call number to be valid.  However, I
-     can't find any unused system call, so use fcntl instead, with
-     invalid arguments.  */
-  regs.SYSCALL_NUM_REG = 72;
-  old_w1 = regs.regs[1];
-  old_w2 = regs.regs[2];
-  regs.regs[0] = -1;
-  regs.regs[1] = -1;
-  regs.regs[2] = -1;
-#endif /* !__aarch64__ */
   regs.STACK_POINTER   = sp;
 
 #ifdef __aarch64__
@@ -924,6 +993,19 @@ process_system_call (struct exec_tracee *tracee)
   if (rc == -1)
     return;
 
+  /* If the process received a signal, see if the signal is SIGSYS and
+     from seccomp.  If so, discard it.  */
+
+  if (WIFSTOPPED (wstatus))
+    {
+      rc = check_signal (tracee, wstatus);
+
+      if (rc == -1)
+       return;
+      else if (rc)
+       goto again1;
+    }
+
   if (!WIFSTOPPED (wstatus))
     /* The process has been killed in response to a signal.  In this
        case, simply unlink the tracee and return.  */
@@ -940,9 +1022,6 @@ process_system_call (struct exec_tracee *tracee)
 
       /* Report errno.  */
 #ifdef __aarch64__
-      /* Restore x1 and x2.  x0 is clobbered by errno.  */
-      regs.regs[1] = old_w1;
-      regs.regs[2] = old_w2;
       aarch64_set_regs (tracee->pid, &regs, false);
 #else /* !__aarch64__ */
       ptrace (PTRACE_SETREGS, tracee->pid, NULL, &regs);
@@ -966,9 +1045,6 @@ process_system_call (struct exec_tracee *tracee)
 
       /* Report errno.  */
 #ifdef __aarch64__
-      /* Restore x1 and x2.  x0 is clobbered by errno.  */
-      regs.regs[1] = old_w1;
-      regs.regs[2] = old_w2;
       aarch64_set_regs (tracee->pid, &regs, false);
 #else /* !__aarch64__ */
       ptrace (PTRACE_SETREGS, tracee->pid, NULL, &regs);