diff options
| author | Po Lu | 2023-05-01 21:23:12 +0800 |
|---|---|---|
| committer | Po Lu | 2023-05-01 21:23:12 +0800 |
| commit | b9de6e35b79cbc10909a856df6b1caa770bd4ac4 (patch) | |
| tree | 6cfbd5ef7419bcd80f26443b134cc1b3e5754780 /exec | |
| parent | da6f0d9c6fd4b2a097f02a6e8f1b2aa33a6bf307 (diff) | |
| download | emacs-b9de6e35b79cbc10909a856df6b1caa770bd4ac4.tar.gz emacs-b9de6e35b79cbc10909a856df6b1caa770bd4ac4.zip | |
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.c | 53 | ||||
| -rw-r--r-- | exec/trace.c | 39 |
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/>. */ | |||
| 26 | #include <assert.h> | 26 | #include <assert.h> |
| 27 | #include <string.h> | 27 | #include <string.h> |
| 28 | #include <ctype.h> | 28 | #include <ctype.h> |
| 29 | #include <stdlib.h> | ||
| 29 | 30 | ||
| 30 | #include <sys/ptrace.h> | 31 | #include <sys/ptrace.h> |
| 31 | #include <sys/param.h> | 32 | #include <sys/param.h> |
| @@ -808,6 +809,35 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs, | |||
| 808 | 809 | ||
| 809 | 810 | ||
| 810 | 811 | ||
| 812 | /* Format PID, an unsigned process identifier, in base 10. Place the | ||
| 813 | result in *IN, and return a pointer to the byte after the | ||
| 814 | result. REM should be NULL. */ | ||
| 815 | |||
| 816 | static char * | ||
| 817 | format_pid (char *in, unsigned int pid) | ||
| 818 | { | ||
| 819 | unsigned int digits[32], *fill; | ||
| 820 | |||
| 821 | fill = digits; | ||
| 822 | |||
| 823 | for (; pid != 0; pid = pid / 10) | ||
| 824 | *fill++ = pid % 10; | ||
| 825 | |||
| 826 | /* Insert 0 if the number would otherwise be empty. */ | ||
| 827 | |||
| 828 | if (fill == digits) | ||
| 829 | *fill++ = 0; | ||
| 830 | |||
| 831 | while (fill != digits) | ||
| 832 | { | ||
| 833 | --fill; | ||
| 834 | *in++ = '0' + *fill; | ||
| 835 | } | ||
| 836 | |||
| 837 | *in = '\0'; | ||
| 838 | return in; | ||
| 839 | } | ||
| 840 | |||
| 811 | /* Return a sequence of actions required to load the executable under | 841 | /* Return a sequence of actions required to load the executable under |
| 812 | the file NAME for the given TRACEE. First, see if the file starts | 842 | the file NAME for the given TRACEE. First, see if the file starts |
| 813 | with #!; in that case, find the program to open and use that | 843 | 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, | |||
| 836 | #if defined __mips__ && !defined MIPS_NABI | 866 | #if defined __mips__ && !defined MIPS_NABI |
| 837 | int fpu_mode; | 867 | int fpu_mode; |
| 838 | #endif /* defined __mips__ && !defined MIPS_NABI */ | 868 | #endif /* defined __mips__ && !defined MIPS_NABI */ |
| 869 | char buffer[PATH_MAX + 80], *rewrite; | ||
| 870 | size_t remaining; | ||
| 871 | |||
| 872 | /* If name is not absolute, then make it relative to TRACEE's | ||
| 873 | cwd. Use stpcpy, as sprintf is not reentrant. */ | ||
| 874 | |||
| 875 | if (name[0] && name[0] != '/') | ||
| 876 | { | ||
| 877 | /* Clear `buffer'. */ | ||
| 878 | memset (buffer, 0, sizeof buffer); | ||
| 879 | |||
| 880 | /* Copy over /proc, the PID, and /cwd/. */ | ||
| 881 | rewrite = stpcpy (buffer, "/proc/"); | ||
| 882 | rewrite = format_pid (rewrite, tracee->pid); | ||
| 883 | rewrite = stpcpy (rewrite, "/cwd/"); | ||
| 884 | |||
| 885 | /* Make sure there is enough free space. */ | ||
| 886 | remaining = buffer + sizeof buffer - rewrite - 1; | ||
| 887 | rewrite = stpncpy (rewrite, name, remaining); | ||
| 888 | |||
| 889 | /* Replace name with buffer. */ | ||
| 890 | name = buffer; | ||
| 891 | } | ||
| 839 | 892 | ||
| 840 | fd = open (name, O_RDONLY); | 893 | fd = open (name, O_RDONLY); |
| 841 | if (fd < 0) | 894 | 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) | |||
| 457 | memcpy (&original, regs, sizeof *regs); | 457 | memcpy (&original, regs, sizeof *regs); |
| 458 | 458 | ||
| 459 | /* Figure out what the loader needs to do. */ | 459 | /* Figure out what the loader needs to do. */ |
| 460 | again1: | ||
| 460 | area = exec_0 (buffer, tracee, &size, regs); | 461 | area = exec_0 (buffer, tracee, &size, regs); |
| 461 | 462 | ||
| 462 | if (!area) | 463 | if (!area) |
| 463 | return 1; | 464 | { |
| 465 | /* Handle SIGINTR errors caused by IO. */ | ||
| 466 | if (errno == EINTR) | ||
| 467 | goto again1; | ||
| 468 | |||
| 469 | return 1; | ||
| 470 | } | ||
| 464 | 471 | ||
| 465 | /* Rewrite the first argument to point to the loader. */ | 472 | /* Rewrite the first argument to point to the loader. */ |
| 466 | 473 | ||
| @@ -516,10 +523,7 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 516 | goto again; | 523 | goto again; |
| 517 | 524 | ||
| 518 | if (rc < 0) | 525 | if (rc < 0) |
| 519 | { | 526 | return 1; |
| 520 | errno = EIO; | ||
| 521 | return 1; | ||
| 522 | } | ||
| 523 | 527 | ||
| 524 | if (!WIFSTOPPED (wstatus)) | 528 | if (!WIFSTOPPED (wstatus)) |
| 525 | /* The process has been killed in response to a signal. | 529 | /* The process has been killed in response to a signal. |
| @@ -608,13 +612,14 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 608 | 612 | ||
| 609 | #endif /* STACK_GROWS_DOWNWARDS */ | 613 | #endif /* STACK_GROWS_DOWNWARDS */ |
| 610 | 614 | ||
| 611 | exec_failure: | ||
| 612 | |||
| 613 | /* Continue. */ | 615 | /* Continue. */ |
| 614 | if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0)) | 616 | if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0)) |
| 615 | return 3; | 617 | return 3; |
| 616 | 618 | ||
| 617 | return 0; | 619 | return 0; |
| 620 | |||
| 621 | exec_failure: | ||
| 622 | return 3; | ||
| 618 | } | 623 | } |
| 619 | 624 | ||
| 620 | /* Process the system call at which TRACEE is stopped. If the system | 625 | /* Process the system call at which TRACEE is stopped. If the system |
| @@ -625,10 +630,10 @@ static void | |||
| 625 | process_system_call (struct exec_tracee *tracee) | 630 | process_system_call (struct exec_tracee *tracee) |
| 626 | { | 631 | { |
| 627 | USER_REGS_STRUCT regs; | 632 | USER_REGS_STRUCT regs; |
| 628 | int rc, wstatus; | 633 | int rc, wstatus, save_errno; |
| 629 | USER_WORD callno, sp; | 634 | USER_WORD callno, sp; |
| 630 | #ifdef __aarch64__ | 635 | #ifdef __aarch64__ |
| 631 | USER_WORD old_w0, old_w1, old_w2; | 636 | USER_WORD old_w1, old_w2; |
| 632 | #endif /* __aarch64__ */ | 637 | #endif /* __aarch64__ */ |
| 633 | 638 | ||
| 634 | #ifdef __aarch64__ | 639 | #ifdef __aarch64__ |
| @@ -695,6 +700,9 @@ process_system_call (struct exec_tracee *tracee) | |||
| 695 | Make sure that the stack pointer is restored to its original | 700 | Make sure that the stack pointer is restored to its original |
| 696 | position upon exit, or bad things can happen. */ | 701 | position upon exit, or bad things can happen. */ |
| 697 | 702 | ||
| 703 | /* First, save errno; system calls below will clobber it. */ | ||
| 704 | save_errno = errno; | ||
| 705 | |||
| 698 | #ifndef __aarch64__ | 706 | #ifndef __aarch64__ |
| 699 | regs.SYSCALL_NUM_REG = -1; | 707 | regs.SYSCALL_NUM_REG = -1; |
| 700 | #else /* __aarch64__ */ | 708 | #else /* __aarch64__ */ |
| @@ -702,7 +710,6 @@ process_system_call (struct exec_tracee *tracee) | |||
| 702 | can't find any unused system call, so use fcntl instead, with | 710 | can't find any unused system call, so use fcntl instead, with |
| 703 | invalid arguments. */ | 711 | invalid arguments. */ |
| 704 | regs.SYSCALL_NUM_REG = 72; | 712 | regs.SYSCALL_NUM_REG = 72; |
| 705 | old_w0 = regs.regs[0]; | ||
| 706 | old_w1 = regs.regs[1]; | 713 | old_w1 = regs.regs[1]; |
| 707 | old_w2 = regs.regs[2]; | 714 | old_w2 = regs.regs[2]; |
| 708 | regs.regs[0] = -1; | 715 | regs.regs[0] = -1; |
| @@ -739,6 +746,11 @@ process_system_call (struct exec_tracee *tracee) | |||
| 739 | if (rc == -1 && errno == EINTR) | 746 | if (rc == -1 && errno == EINTR) |
| 740 | goto again1; | 747 | goto again1; |
| 741 | 748 | ||
| 749 | /* Return if waitpid fails. */ | ||
| 750 | |||
| 751 | if (rc == -1) | ||
| 752 | return; | ||
| 753 | |||
| 742 | if (!WIFSTOPPED (wstatus)) | 754 | if (!WIFSTOPPED (wstatus)) |
| 743 | /* The process has been killed in response to a signal. In this | 755 | /* The process has been killed in response to a signal. In this |
| 744 | case, simply unlink the tracee and return. */ | 756 | case, simply unlink the tracee and return. */ |
| @@ -747,16 +759,15 @@ process_system_call (struct exec_tracee *tracee) | |||
| 747 | { | 759 | { |
| 748 | #ifdef __mips__ | 760 | #ifdef __mips__ |
| 749 | /* MIPS systems place errno in v0 and set a3 to 1. */ | 761 | /* MIPS systems place errno in v0 and set a3 to 1. */ |
| 750 | regs.gregs[2] = errno; | 762 | regs.gregs[2] = save_errno; |
| 751 | regs.gregs[7] = 1; | 763 | regs.gregs[7] = 1; |
| 752 | #else /* !__mips__ */ | 764 | #else /* !__mips__ */ |
| 753 | regs.SYSCALL_RET_REG = -errno; | 765 | regs.SYSCALL_RET_REG = -save_errno; |
| 754 | #endif /* __mips__ */ | 766 | #endif /* __mips__ */ |
| 755 | 767 | ||
| 756 | /* Report errno. */ | 768 | /* Report errno. */ |
| 757 | #ifdef __aarch64__ | 769 | #ifdef __aarch64__ |
| 758 | /* Restore x0, x1 and x2. */ | 770 | /* Restore x1 and x2. x0 is clobbered by errno. */ |
| 759 | regs.regs[0] = old_w0; | ||
| 760 | regs.regs[1] = old_w1; | 771 | regs.regs[1] = old_w1; |
| 761 | regs.regs[2] = old_w2; | 772 | regs.regs[2] = old_w2; |
| 762 | aarch64_set_regs (tracee->pid, ®s, false); | 773 | aarch64_set_regs (tracee->pid, ®s, false); |