diff options
| author | Po Lu | 2023-05-04 09:12:26 +0800 |
|---|---|---|
| committer | Po Lu | 2023-05-04 09:12:26 +0800 |
| commit | 339cdef28e6c78e71b310ade3ffd22333cbb0089 (patch) | |
| tree | 913505b2a1091ca9e5ecf792f558876c859f5750 /exec | |
| parent | 19210f8b771947ad10fdaaf27c4f2a177ece3631 (diff) | |
| download | emacs-339cdef28e6c78e71b310ade3ffd22333cbb0089.tar.gz emacs-339cdef28e6c78e71b310ade3ffd22333cbb0089.zip | |
Update Android port
* exec/trace.c (check_signal): New function.
(handle_exec, process_system_call): Handle signal-delivery-stop
while waiting synchronously for syscall completion.
Diffstat (limited to 'exec')
| -rw-r--r-- | exec/trace.c | 118 |
1 files changed, 97 insertions, 21 deletions
diff --git a/exec/trace.c b/exec/trace.c index 579a62f6c5e..f9dd4d419f4 100644 --- a/exec/trace.c +++ b/exec/trace.c | |||
| @@ -451,6 +451,8 @@ handle_clone (pid_t pid) | |||
| 451 | /* File name of the loader binary. */ | 451 | /* File name of the loader binary. */ |
| 452 | static const char *loader_name; | 452 | static const char *loader_name; |
| 453 | 453 | ||
| 454 | |||
| 455 | |||
| 454 | /* Return whether or not the trap signal described by SIGNAL is | 456 | /* Return whether or not the trap signal described by SIGNAL is |
| 455 | generated by a system call being attempted by a tracee. */ | 457 | generated by a system call being attempted by a tracee. */ |
| 456 | 458 | ||
| @@ -463,6 +465,79 @@ syscall_trap_p (siginfo_t *signal) | |||
| 463 | || signal->si_code == (SIGTRAP | SI_KERNEL)); | 465 | || signal->si_code == (SIGTRAP | SI_KERNEL)); |
| 464 | } | 466 | } |
| 465 | 467 | ||
| 468 | /* Check if the wait status STATUS indicates a system call trap. | ||
| 469 | TRACEE is the process whose stop STATUS describes. If TRACEE exits | ||
| 470 | while this information is being determined, return -1; if STATUS | ||
| 471 | indicates some other kind of stop, return 1 after continuing | ||
| 472 | TRACEE. Value is 0 otherwise. */ | ||
| 473 | |||
| 474 | static int | ||
| 475 | check_signal (struct exec_tracee *tracee, int status) | ||
| 476 | { | ||
| 477 | siginfo_t siginfo; | ||
| 478 | |||
| 479 | switch ((status & 0xfff00) >> 8) | ||
| 480 | { | ||
| 481 | case SIGTRAP: | ||
| 482 | /* Now, use PTRACE_GETSIGINFO to determine whether or not the | ||
| 483 | signal was delivered in response to a system call. */ | ||
| 484 | |||
| 485 | if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo)) | ||
| 486 | return -1; | ||
| 487 | |||
| 488 | if (!syscall_trap_p (&siginfo)) | ||
| 489 | { | ||
| 490 | if (siginfo.si_code < 0) | ||
| 491 | /* SIGTRAP delivered from userspace. Pass it on. */ | ||
| 492 | ptrace (PTRACE_SYSCALL, tracee->pid, 0, SIGTRAP); | ||
| 493 | else | ||
| 494 | ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0); | ||
| 495 | |||
| 496 | return 1; | ||
| 497 | } | ||
| 498 | |||
| 499 | case SIGTRAP | 0x80: /* SIGTRAP | 0x80 specifically refers to | ||
| 500 | system call traps. */ | ||
| 501 | break; | ||
| 502 | |||
| 503 | #ifdef SIGSYS | ||
| 504 | case SIGSYS: | ||
| 505 | if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo)) | ||
| 506 | return -1; | ||
| 507 | |||
| 508 | /* Continue the process until the next syscall, but don't | ||
| 509 | pass through the signal if an emulated syscall led to | ||
| 510 | it. */ | ||
| 511 | #ifdef HAVE_SIGINFO_T_SI_SYSCALL | ||
| 512 | #ifndef __arm__ | ||
| 513 | ptrace (PTRACE_SYSCALL, tracee->pid, | ||
| 514 | 0, ((siginfo.si_code == SYS_SECCOMP | ||
| 515 | && siginfo.si_syscall == -1) | ||
| 516 | ? 0 : status)); | ||
| 517 | #else /* __arm__ */ | ||
| 518 | ptrace (PTRACE_SYSCALL, tracee->pid, | ||
| 519 | 0, ((siginfo.si_code == SYS_SECCOMP | ||
| 520 | && siginfo.si_syscall == 222) | ||
| 521 | ? 0 : status)); | ||
| 522 | #endif /* !__arm__ */ | ||
| 523 | #else /* !HAVE_SIGINFO_T_SI_SYSCALL */ | ||
| 524 | /* Drop this signal, since what caused it is unknown. */ | ||
| 525 | ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0); | ||
| 526 | #endif /* HAVE_SIGINFO_T_SI_SYSCALL */ | ||
| 527 | return 1; | ||
| 528 | #endif /* SIGSYS */ | ||
| 529 | |||
| 530 | default: | ||
| 531 | /* Continue the process until the next syscall. */ | ||
| 532 | ptrace (PTRACE_SYSCALL, tracee->pid, 0, status); | ||
| 533 | return 1; | ||
| 534 | } | ||
| 535 | |||
| 536 | return 0; | ||
| 537 | } | ||
| 538 | |||
| 539 | |||
| 540 | |||
| 466 | /* Handle an `exec' system call from the given TRACEE. REGS are the | 541 | /* Handle an `exec' system call from the given TRACEE. REGS are the |
| 467 | tracee's current user-mode registers. | 542 | tracee's current user-mode registers. |
| 468 | 543 | ||
| @@ -591,6 +666,15 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 591 | return 2; | 666 | return 2; |
| 592 | else | 667 | else |
| 593 | { | 668 | { |
| 669 | /* Then, check if STATUS is not a syscall-stop, and try again if | ||
| 670 | it isn't. */ | ||
| 671 | rc = check_signal (tracee, wstatus); | ||
| 672 | |||
| 673 | if (rc == -1) | ||
| 674 | return 2; | ||
| 675 | else if (rc) | ||
| 676 | goto again; | ||
| 677 | |||
| 594 | /* Retrieve the signal information and determine whether or not | 678 | /* Retrieve the signal information and determine whether or not |
| 595 | the system call has completed. */ | 679 | the system call has completed. */ |
| 596 | 680 | ||
| @@ -777,9 +861,6 @@ process_system_call (struct exec_tracee *tracee) | |||
| 777 | USER_REGS_STRUCT regs; | 861 | USER_REGS_STRUCT regs; |
| 778 | int rc, wstatus, save_errno; | 862 | int rc, wstatus, save_errno; |
| 779 | USER_WORD callno, sp; | 863 | USER_WORD callno, sp; |
| 780 | #ifdef __aarch64__ | ||
| 781 | USER_WORD old_w1, old_w2; | ||
| 782 | #endif /* __aarch64__ */ | ||
| 783 | USER_WORD result; | 864 | USER_WORD result; |
| 784 | bool reporting_error; | 865 | bool reporting_error; |
| 785 | 866 | ||
| @@ -876,19 +957,7 @@ process_system_call (struct exec_tracee *tracee) | |||
| 876 | /* First, save errno; system calls below will clobber it. */ | 957 | /* First, save errno; system calls below will clobber it. */ |
| 877 | save_errno = errno; | 958 | save_errno = errno; |
| 878 | 959 | ||
| 879 | #ifndef __aarch64__ | ||
| 880 | regs.SYSCALL_NUM_REG = -1; | 960 | regs.SYSCALL_NUM_REG = -1; |
| 881 | #else /* __aarch64__ */ | ||
| 882 | /* ARM also requires the system call number to be valid. However, I | ||
| 883 | can't find any unused system call, so use fcntl instead, with | ||
| 884 | invalid arguments. */ | ||
| 885 | regs.SYSCALL_NUM_REG = 72; | ||
| 886 | old_w1 = regs.regs[1]; | ||
| 887 | old_w2 = regs.regs[2]; | ||
| 888 | regs.regs[0] = -1; | ||
| 889 | regs.regs[1] = -1; | ||
| 890 | regs.regs[2] = -1; | ||
| 891 | #endif /* !__aarch64__ */ | ||
| 892 | regs.STACK_POINTER = sp; | 961 | regs.STACK_POINTER = sp; |
| 893 | 962 | ||
| 894 | #ifdef __aarch64__ | 963 | #ifdef __aarch64__ |
| @@ -924,6 +993,19 @@ process_system_call (struct exec_tracee *tracee) | |||
| 924 | if (rc == -1) | 993 | if (rc == -1) |
| 925 | return; | 994 | return; |
| 926 | 995 | ||
| 996 | /* If the process received a signal, see if the signal is SIGSYS and | ||
| 997 | from seccomp. If so, discard it. */ | ||
| 998 | |||
| 999 | if (WIFSTOPPED (wstatus)) | ||
| 1000 | { | ||
| 1001 | rc = check_signal (tracee, wstatus); | ||
| 1002 | |||
| 1003 | if (rc == -1) | ||
| 1004 | return; | ||
| 1005 | else if (rc) | ||
| 1006 | goto again1; | ||
| 1007 | } | ||
| 1008 | |||
| 927 | if (!WIFSTOPPED (wstatus)) | 1009 | if (!WIFSTOPPED (wstatus)) |
| 928 | /* The process has been killed in response to a signal. In this | 1010 | /* The process has been killed in response to a signal. In this |
| 929 | case, simply unlink the tracee and return. */ | 1011 | case, simply unlink the tracee and return. */ |
| @@ -940,9 +1022,6 @@ process_system_call (struct exec_tracee *tracee) | |||
| 940 | 1022 | ||
| 941 | /* Report errno. */ | 1023 | /* Report errno. */ |
| 942 | #ifdef __aarch64__ | 1024 | #ifdef __aarch64__ |
| 943 | /* Restore x1 and x2. x0 is clobbered by errno. */ | ||
| 944 | regs.regs[1] = old_w1; | ||
| 945 | regs.regs[2] = old_w2; | ||
| 946 | aarch64_set_regs (tracee->pid, ®s, false); | 1025 | aarch64_set_regs (tracee->pid, ®s, false); |
| 947 | #else /* !__aarch64__ */ | 1026 | #else /* !__aarch64__ */ |
| 948 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s); | 1027 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s); |
| @@ -966,9 +1045,6 @@ process_system_call (struct exec_tracee *tracee) | |||
| 966 | 1045 | ||
| 967 | /* Report errno. */ | 1046 | /* Report errno. */ |
| 968 | #ifdef __aarch64__ | 1047 | #ifdef __aarch64__ |
| 969 | /* Restore x1 and x2. x0 is clobbered by errno. */ | ||
| 970 | regs.regs[1] = old_w1; | ||
| 971 | regs.regs[2] = old_w2; | ||
| 972 | aarch64_set_regs (tracee->pid, ®s, false); | 1048 | aarch64_set_regs (tracee->pid, ®s, false); |
| 973 | #else /* !__aarch64__ */ | 1049 | #else /* !__aarch64__ */ |
| 974 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s); | 1050 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s); |