]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix cwd relative process execution on Android
authorPo Lu <luangruo@yahoo.com>
Mon, 1 May 2023 13:23:12 +0000 (21:23 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 1 May 2023 13:23:12 +0000 (21:23 +0800)
* exec/exec.c (format_pid): New function.
(exec_0): Make cwd relative file names relative to
/proc/pid/cwd.
* exec/trace.c (handle_exec): Handle EINTR.
(process_system_call): Report failure without clobbering x0.

exec/exec.c
exec/trace.c

index 662c8bf69d211492b0771e25fe93914a972e76fe..c7a73f221f54f1d42a0dc8a17486362ef9469c5a 100644 (file)
@@ -26,6 +26,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <assert.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdlib.h>
 
 #include <sys/ptrace.h>
 #include <sys/param.h>
@@ -808,6 +809,35 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs,
 
 \f
 
+/* Format PID, an unsigned process identifier, in base 10.  Place the
+   result in *IN, and return a pointer to the byte after the
+   result.  REM should be NULL.  */
+
+static char *
+format_pid (char *in, unsigned int pid)
+{
+  unsigned int digits[32], *fill;
+
+  fill = digits;
+
+  for (; pid != 0; pid = pid / 10)
+    *fill++ = pid % 10;
+
+  /* Insert 0 if the number would otherwise be empty.  */
+
+  if (fill == digits)
+    *fill++ = 0;
+
+  while (fill != digits)
+    {
+      --fill;
+      *in++ = '0' + *fill;
+    }
+
+  *in = '\0';
+  return in;
+}
+
 /* Return a sequence of actions required to load the executable under
    the file NAME for the given TRACEE.  First, see if the file starts
    with #!; in that case, find the program to open and use that
@@ -836,6 +866,29 @@ exec_0 (const char *name, struct exec_tracee *tracee,
 #if defined __mips__ && !defined MIPS_NABI
   int fpu_mode;
 #endif /* defined __mips__ && !defined MIPS_NABI */
+  char buffer[PATH_MAX + 80], *rewrite;
+  size_t remaining;
+
+  /* If name is not absolute, then make it relative to TRACEE's
+     cwd.  Use stpcpy, as sprintf is not reentrant.  */
+
+  if (name[0] && name[0] != '/')
+    {
+      /* Clear `buffer'.  */
+      memset (buffer, 0, sizeof buffer);
+
+      /* Copy over /proc, the PID, and /cwd/.  */
+      rewrite = stpcpy (buffer, "/proc/");
+      rewrite = format_pid (rewrite, tracee->pid);
+      rewrite = stpcpy (rewrite, "/cwd/");
+
+      /* Make sure there is enough free space.  */
+      remaining = buffer + sizeof buffer - rewrite - 1;
+      rewrite = stpncpy (rewrite, name, remaining);
+
+      /* Replace name with buffer.  */
+      name = buffer;
+    }
 
   fd = open (name, O_RDONLY);
   if (fd < 0)
index df5deacd9bbc8343c1e61586f6c5810dbdd88ef5..d9e8673ba716c08b828a4c550d2a799479734aae 100644 (file)
@@ -457,10 +457,17 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
   memcpy (&original, regs, sizeof *regs);
 
   /* Figure out what the loader needs to do.  */
+ again1:
   area = exec_0 (buffer, tracee, &size, regs);
 
   if (!area)
-    return 1;
+    {
+      /* Handle SIGINTR errors caused by IO.  */
+      if (errno == EINTR)
+       goto again1;
+
+      return 1;
+    }
 
   /* Rewrite the first argument to point to the loader.  */
 
@@ -516,10 +523,7 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
     goto again;
 
   if (rc < 0)
-    {
-      errno = EIO;
-      return 1;
-    }
+    return 1;
 
   if (!WIFSTOPPED (wstatus))
     /* The process has been killed in response to a signal.
@@ -608,13 +612,14 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
 
 #endif /* STACK_GROWS_DOWNWARDS */
 
- exec_failure:
-
   /* Continue.  */
   if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0))
     return 3;
 
   return 0;
+
+ exec_failure:
+  return 3;
 }
 
 /* Process the system call at which TRACEE is stopped.  If the system
@@ -625,10 +630,10 @@ static void
 process_system_call (struct exec_tracee *tracee)
 {
   USER_REGS_STRUCT regs;
-  int rc, wstatus;
+  int rc, wstatus, save_errno;
   USER_WORD callno, sp;
 #ifdef __aarch64__
-  USER_WORD old_w0, old_w1, old_w2;
+  USER_WORD old_w1, old_w2;
 #endif /* __aarch64__ */
 
 #ifdef __aarch64__
@@ -695,6 +700,9 @@ process_system_call (struct exec_tracee *tracee)
      Make sure that the stack pointer is restored to its original
      position upon exit, or bad things can happen.  */
 
+  /* First, save errno; system calls below will clobber it.  */
+  save_errno = errno;
+
 #ifndef __aarch64__
   regs.SYSCALL_NUM_REG = -1;
 #else /* __aarch64__ */
@@ -702,7 +710,6 @@ process_system_call (struct exec_tracee *tracee)
      can't find any unused system call, so use fcntl instead, with
      invalid arguments.  */
   regs.SYSCALL_NUM_REG = 72;
-  old_w0 = regs.regs[0];
   old_w1 = regs.regs[1];
   old_w2 = regs.regs[2];
   regs.regs[0] = -1;
@@ -739,6 +746,11 @@ process_system_call (struct exec_tracee *tracee)
   if (rc == -1 && errno == EINTR)
     goto again1;
 
+  /* Return if waitpid fails.  */
+
+  if (rc == -1)
+    return;
+
   if (!WIFSTOPPED (wstatus))
     /* The process has been killed in response to a signal.  In this
        case, simply unlink the tracee and return.  */
@@ -747,16 +759,15 @@ process_system_call (struct exec_tracee *tracee)
     {
 #ifdef __mips__
       /* MIPS systems place errno in v0 and set a3 to 1.  */
-      regs.gregs[2] = errno;
+      regs.gregs[2] = save_errno;
       regs.gregs[7] = 1;
 #else /* !__mips__ */
-      regs.SYSCALL_RET_REG = -errno;
+      regs.SYSCALL_RET_REG = -save_errno;
 #endif /* __mips__ */
 
       /* Report errno.  */
 #ifdef __aarch64__
-      /* Restore x0, x1 and x2.  */
-      regs.regs[0] = old_w0;
+      /* 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);