diff options
| author | Po Lu | 2023-05-02 20:45:57 +0800 |
|---|---|---|
| committer | Po Lu | 2023-05-02 20:45:57 +0800 |
| commit | c47716f95b8fda9438047d2683a415a65c18ecbd (patch) | |
| tree | 947c45293556f41ce02426889890b3442f2b7b36 /exec/trace.c | |
| parent | f4512cca0b996e5343ebe57511f45a29f64c4a8e (diff) | |
| download | emacs-c47716f95b8fda9438047d2683a415a65c18ecbd.tar.gz emacs-c47716f95b8fda9438047d2683a415a65c18ecbd.zip | |
Update Android port
* exec/config.h.in (__bool_true_false_are_defined):
* exec/configure.ac (REENTRANT): New definition.
(READLINKAT_SYSCALL, READLINK_SYSCALL): New defines. Set on all
hosts.
* exec/exec.c (MIN, MAX): Remove redundant declarations. Move
to config.h.
(exec_0): Copy name of executable into NAME when !REENTRANT.
* exec/exec.h (struct exec_tracee): New struct `exec_file'.
* exec/trace.c (remove_tracee, handle_exec, handle_readlinkat)
(process_system_call, after_fork): Handle readlinkat system
calls.
Diffstat (limited to 'exec/trace.c')
| -rw-r--r-- | exec/trace.c | 168 |
1 files changed, 164 insertions, 4 deletions
diff --git a/exec/trace.c b/exec/trace.c index d9e8673ba71..cb0839c9cd9 100644 --- a/exec/trace.c +++ b/exec/trace.c | |||
| @@ -315,6 +315,13 @@ remove_tracee (struct exec_tracee *tracee) | |||
| 315 | 315 | ||
| 316 | /* Link the tracee onto the list of free tracees. */ | 316 | /* Link the tracee onto the list of free tracees. */ |
| 317 | tracee->next = free_tracees; | 317 | tracee->next = free_tracees; |
| 318 | |||
| 319 | #ifndef REENTRANT | ||
| 320 | /* Free the exec file, if any. */ | ||
| 321 | free (tracee->exec_file); | ||
| 322 | tracee->exec_file = NULL; | ||
| 323 | #endif /* REENTRANT */ | ||
| 324 | |||
| 318 | free_tracees = tracee; | 325 | free_tracees = tracee; |
| 319 | 326 | ||
| 320 | return; | 327 | return; |
| @@ -431,7 +438,7 @@ syscall_trap_p (siginfo_t *signal) | |||
| 431 | static int | 438 | static int |
| 432 | handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | 439 | handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) |
| 433 | { | 440 | { |
| 434 | char buffer[PATH_MAX], *area; | 441 | char buffer[PATH_MAX + 80], *area; |
| 435 | USER_REGS_STRUCT original; | 442 | USER_REGS_STRUCT original; |
| 436 | size_t size, loader_size; | 443 | size_t size, loader_size; |
| 437 | USER_WORD loader, size1, sp; | 444 | USER_WORD loader, size1, sp; |
| @@ -517,6 +524,17 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 517 | return 1; | 524 | return 1; |
| 518 | } | 525 | } |
| 519 | 526 | ||
| 527 | #ifndef REENTRANT | ||
| 528 | /* Now that the loader has started, record the value to use for | ||
| 529 | /proc/self/exe. Don't give up just because strdup fails. | ||
| 530 | |||
| 531 | Note that exec_0 copies the absolute file name into buffer. */ | ||
| 532 | |||
| 533 | if (tracee->exec_file) | ||
| 534 | free (tracee->exec_file); | ||
| 535 | tracee->exec_file = strdup (buffer); | ||
| 536 | #endif /* REENTRANT */ | ||
| 537 | |||
| 520 | again: | 538 | again: |
| 521 | rc = waitpid (tracee->pid, &wstatus, __WALL); | 539 | rc = waitpid (tracee->pid, &wstatus, __WALL); |
| 522 | if (rc == -1 && errno == EINTR) | 540 | if (rc == -1 && errno == EINTR) |
| @@ -622,6 +640,91 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 622 | return 3; | 640 | return 3; |
| 623 | } | 641 | } |
| 624 | 642 | ||
| 643 | /* Handle a `readlink' or `readlinkat' system call. | ||
| 644 | |||
| 645 | CALLNO is the system call number, and REGS are the current user | ||
| 646 | registers of the TRACEE. | ||
| 647 | |||
| 648 | If the first argument of a `readlinkat' system call is AT_FDCWD, | ||
| 649 | and the file name specified in either a `readlink' or `readlinkat' | ||
| 650 | system call is `/proc/self/exe', write the name of the executable | ||
| 651 | being run into the buffer specified in the system call. | ||
| 652 | |||
| 653 | Return the number of bytes written to the tracee's buffer in | ||
| 654 | *RESULT. | ||
| 655 | |||
| 656 | Value is 0 upon success. Value is 1 upon failure, and 2 if the | ||
| 657 | system call has been emulated. */ | ||
| 658 | |||
| 659 | static int | ||
| 660 | handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs, | ||
| 661 | struct exec_tracee *tracee, USER_WORD *result) | ||
| 662 | { | ||
| 663 | #ifdef REENTRANT | ||
| 664 | /* readlinkat cannot be handled specially when the library is built | ||
| 665 | to be reentrant, as the file name information cannot be | ||
| 666 | recorded. */ | ||
| 667 | return 0; | ||
| 668 | #else /* !REENTRANT */ | ||
| 669 | |||
| 670 | char buffer[PATH_MAX + 1]; | ||
| 671 | USER_WORD address, return_buffer, size; | ||
| 672 | size_t length; | ||
| 673 | |||
| 674 | /* Read the file name. */ | ||
| 675 | |||
| 676 | #ifdef READLINK_SYSCALL | ||
| 677 | if (callno == READLINK_SYSCALL) | ||
| 678 | { | ||
| 679 | address = regs->SYSCALL_ARG_REG; | ||
| 680 | return_buffer = regs->SYSCALL_ARG1_REG; | ||
| 681 | size = regs->SYSCALL_ARG2_REG; | ||
| 682 | } | ||
| 683 | else | ||
| 684 | #endif /* READLINK_SYSCALL */ | ||
| 685 | { | ||
| 686 | address = regs->SYSCALL_ARG1_REG; | ||
| 687 | return_buffer = regs->SYSCALL_ARG2_REG; | ||
| 688 | size = regs->SYSCALL_ARG3_REG; | ||
| 689 | } | ||
| 690 | |||
| 691 | read_memory (tracee, buffer, PATH_MAX, address); | ||
| 692 | |||
| 693 | /* Make sure BUFFER is NULL terminated. */ | ||
| 694 | |||
| 695 | if (!memchr (buffer, '\0', PATH_MAX)) | ||
| 696 | { | ||
| 697 | errno = ENAMETOOLONG; | ||
| 698 | return 1; | ||
| 699 | } | ||
| 700 | |||
| 701 | /* Now check if the caller is looking for /proc/self/exe. | ||
| 702 | |||
| 703 | dirfd can be ignored, as for now only absolute file names are | ||
| 704 | handled. FIXME. */ | ||
| 705 | |||
| 706 | if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file) | ||
| 707 | return 0; | ||
| 708 | |||
| 709 | /* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or | ||
| 710 | size, whichever is less. */ | ||
| 711 | |||
| 712 | length = strlen (tracee->exec_file); | ||
| 713 | length = MIN (size, MIN (PATH_MAX, length)); | ||
| 714 | strncpy (buffer, tracee->exec_file, length); | ||
| 715 | |||
| 716 | if (user_copy (tracee, (unsigned char *) buffer, | ||
| 717 | return_buffer, length)) | ||
| 718 | { | ||
| 719 | errno = EIO; | ||
| 720 | return 1; | ||
| 721 | } | ||
| 722 | |||
| 723 | *result = length; | ||
| 724 | return 2; | ||
| 725 | #endif /* REENTRANT */ | ||
| 726 | } | ||
| 727 | |||
| 625 | /* Process the system call at which TRACEE is stopped. If the system | 728 | /* Process the system call at which TRACEE is stopped. If the system |
| 626 | call is not known or not exec, send TRACEE on its way. Otherwise, | 729 | call is not known or not exec, send TRACEE on its way. Otherwise, |
| 627 | rewrite it to load the loader and perform an appropriate action. */ | 730 | rewrite it to load the loader and perform an appropriate action. */ |
| @@ -635,6 +738,8 @@ process_system_call (struct exec_tracee *tracee) | |||
| 635 | #ifdef __aarch64__ | 738 | #ifdef __aarch64__ |
| 636 | USER_WORD old_w1, old_w2; | 739 | USER_WORD old_w1, old_w2; |
| 637 | #endif /* __aarch64__ */ | 740 | #endif /* __aarch64__ */ |
| 741 | USER_WORD result; | ||
| 742 | bool reporting_error; | ||
| 638 | 743 | ||
| 639 | #ifdef __aarch64__ | 744 | #ifdef __aarch64__ |
| 640 | rc = aarch64_get_regs (tracee->pid, ®s); | 745 | rc = aarch64_get_regs (tracee->pid, ®s); |
| @@ -678,6 +783,24 @@ process_system_call (struct exec_tracee *tracee) | |||
| 678 | 783 | ||
| 679 | break; | 784 | break; |
| 680 | 785 | ||
| 786 | #ifdef READLINK_SYSCALL | ||
| 787 | case READLINK_SYSCALL: | ||
| 788 | #endif /* READLINK_SYSCALL */ | ||
| 789 | case READLINKAT_SYSCALL: | ||
| 790 | |||
| 791 | /* Handle this readlinkat system call. */ | ||
| 792 | rc = handle_readlinkat (callno, ®s, tracee, | ||
| 793 | &result); | ||
| 794 | |||
| 795 | /* rc means the same as in `handle_exec'. */ | ||
| 796 | |||
| 797 | if (rc == 1) | ||
| 798 | goto report_syscall_error; | ||
| 799 | else if (rc == 2) | ||
| 800 | goto emulate_syscall; | ||
| 801 | |||
| 802 | /* Fallthrough. */ | ||
| 803 | |||
| 681 | default: | 804 | default: |
| 682 | /* Don't wait for the system call to finish; instead, the system | 805 | /* Don't wait for the system call to finish; instead, the system |
| 683 | will DTRT upon the next call to PTRACE_SYSCALL after the | 806 | will DTRT upon the next call to PTRACE_SYSCALL after the |
| @@ -694,8 +817,16 @@ process_system_call (struct exec_tracee *tracee) | |||
| 694 | return; | 817 | return; |
| 695 | 818 | ||
| 696 | report_syscall_error: | 819 | report_syscall_error: |
| 697 | /* Reporting an error works by setting the system call number to -1, | 820 | reporting_error = true; |
| 698 | letting it continue, and then substituting errno for ENOSYS. | 821 | goto common; |
| 822 | |||
| 823 | emulate_syscall: | ||
| 824 | reporting_error = false; | ||
| 825 | common: | ||
| 826 | |||
| 827 | /* Reporting an error or emulating a system call works by setting | ||
| 828 | the system call number to -1, letting it continue, and then | ||
| 829 | substituting errno for ENOSYS in the case of an error. | ||
| 699 | 830 | ||
| 700 | Make sure that the stack pointer is restored to its original | 831 | Make sure that the stack pointer is restored to its original |
| 701 | position upon exit, or bad things can happen. */ | 832 | position upon exit, or bad things can happen. */ |
| @@ -755,7 +886,7 @@ process_system_call (struct exec_tracee *tracee) | |||
| 755 | /* The process has been killed in response to a signal. In this | 886 | /* The process has been killed in response to a signal. In this |
| 756 | case, simply unlink the tracee and return. */ | 887 | case, simply unlink the tracee and return. */ |
| 757 | remove_tracee (tracee); | 888 | remove_tracee (tracee); |
| 758 | else | 889 | else if (reporting_error) |
| 759 | { | 890 | { |
| 760 | #ifdef __mips__ | 891 | #ifdef __mips__ |
| 761 | /* MIPS systems place errno in v0 and set a3 to 1. */ | 892 | /* MIPS systems place errno in v0 and set a3 to 1. */ |
| @@ -778,6 +909,32 @@ process_system_call (struct exec_tracee *tracee) | |||
| 778 | /* Now wait for the next system call to happen. */ | 909 | /* Now wait for the next system call to happen. */ |
| 779 | ptrace (PTRACE_SYSCALL, tracee->pid, NULL, NULL); | 910 | ptrace (PTRACE_SYSCALL, tracee->pid, NULL, NULL); |
| 780 | } | 911 | } |
| 912 | else | ||
| 913 | { | ||
| 914 | /* No error is being reported. Return the result in the | ||
| 915 | appropriate registers. */ | ||
| 916 | |||
| 917 | #ifdef __mips__ | ||
| 918 | /* MIPS systems place errno in v0 and set a3 to 1. */ | ||
| 919 | regs.gregs[2] = result; | ||
| 920 | regs.gregs[7] = 0; | ||
| 921 | #else /* !__mips__ */ | ||
| 922 | regs.SYSCALL_RET_REG = result; | ||
| 923 | #endif /* __mips__ */ | ||
| 924 | |||
| 925 | /* Report errno. */ | ||
| 926 | #ifdef __aarch64__ | ||
| 927 | /* Restore x1 and x2. x0 is clobbered by errno. */ | ||
| 928 | regs.regs[1] = old_w1; | ||
| 929 | regs.regs[2] = old_w2; | ||
| 930 | aarch64_set_regs (tracee->pid, ®s, false); | ||
| 931 | #else /* !__aarch64__ */ | ||
| 932 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s); | ||
| 933 | #endif /* __aarch64__ */ | ||
| 934 | |||
| 935 | /* Now wait for the next system call to happen. */ | ||
| 936 | ptrace (PTRACE_SYSCALL, tracee->pid, NULL, NULL); | ||
| 937 | } | ||
| 781 | } | 938 | } |
| 782 | 939 | ||
| 783 | 940 | ||
| @@ -869,6 +1026,9 @@ after_fork (pid_t pid) | |||
| 869 | tracee->pid = pid; | 1026 | tracee->pid = pid; |
| 870 | tracee->next = tracing_processes; | 1027 | tracee->next = tracing_processes; |
| 871 | tracee->waiting_for_syscall = false; | 1028 | tracee->waiting_for_syscall = false; |
| 1029 | #ifndef REENTRANT | ||
| 1030 | tracee->exec_file = NULL; | ||
| 1031 | #endif /* REENTRANT */ | ||
| 872 | tracing_processes = tracee; | 1032 | tracing_processes = tracee; |
| 873 | return 0; | 1033 | return 0; |
| 874 | } | 1034 | } |