summaryrefslogtreecommitdiff
path: root/exec
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-05-01 21:23:12 +0800
committerPo Lu <luangruo@yahoo.com>2023-05-01 21:23:12 +0800
commitb9de6e35b79cbc10909a856df6b1caa770bd4ac4 (patch)
tree6cfbd5ef7419bcd80f26443b134cc1b3e5754780 /exec
parentda6f0d9c6fd4b2a097f02a6e8f1b2aa33a6bf307 (diff)
downloademacs-b9de6e35b79cbc10909a856df6b1caa770bd4ac4.tar.gz
Fix cwd relative process execution on Android
* 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.
Diffstat (limited to 'exec')
-rw-r--r--exec/exec.c53
-rw-r--r--exec/trace.c39
2 files changed, 78 insertions, 14 deletions
diff --git a/exec/exec.c b/exec/exec.c
index 662c8bf69d2..c7a73f221f5 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -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,
+/* 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)
diff --git a/exec/trace.c b/exec/trace.c
index df5deacd9bb..d9e8673ba71 100644
--- a/exec/trace.c
+++ b/exec/trace.c
@@ -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);