From: Po Lu Date: Mon, 1 May 2023 13:23:12 +0000 (+0800) Subject: Fix cwd relative process execution on Android X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=b9de6e35b79cbc10909a856df6b1caa770bd4ac4;p=emacs.git 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. --- 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 . */ #include #include #include +#include #include #include @@ -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, ®s, false);