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.
This commit is contained in:
parent
f4512cca0b
commit
c47716f95b
5 changed files with 288 additions and 20 deletions
|
@ -76,6 +76,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
|
@ -115,6 +118,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to number of the `readlinkat' system call. */
|
||||
#undef READLINKAT_SYSCALL
|
||||
|
||||
/* Define to number of the `readlink' system call. */
|
||||
#undef READLINK_SYSCALL
|
||||
|
||||
/* Define to 1 if the library is used within a signal handler. */
|
||||
#undef REENTRANT
|
||||
|
||||
/* Define to 1 if the stack grows downwards. */
|
||||
#undef STACK_GROWS_DOWNWARDS
|
||||
|
||||
|
@ -129,6 +141,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
/* Define to register holding arg1 to system calls. */
|
||||
#undef SYSCALL_ARG1_REG
|
||||
|
||||
/* Define to register holding arg2 to system calls. */
|
||||
#undef SYSCALL_ARG2_REG
|
||||
|
||||
/* Define to register holding arg3 to system calls. */
|
||||
#undef SYSCALL_ARG3_REG
|
||||
|
||||
/* Define to register holding arg0 to system calls. */
|
||||
#undef SYSCALL_ARG_REG
|
||||
|
||||
|
@ -217,3 +235,15 @@ typedef bool _Bool;
|
|||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
|
|
|
@ -42,6 +42,11 @@ General Public License for more details.
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */])
|
||||
|
||||
AC_ARG_WITH([reentrancy],
|
||||
[AS_HELP_STRING([--with-reentrancy],
|
||||
[Generate library which can be used within a signal handler.])],
|
||||
[AC_DEFINE([REENTRANT], [1])])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
|
@ -56,6 +61,7 @@ AC_TYPE_PID_T
|
|||
AC_HEADER_STDBOOL
|
||||
AC_CHECK_FUNCS([getpagesize stpcpy stpncpy])
|
||||
AC_CHECK_DECLS([stpcpy, stpncpy])
|
||||
AC_CHECK_HEADERS([sys/param.h]) dnl for MIN and MAX
|
||||
|
||||
AH_BOTTOM([
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
|
@ -73,6 +79,18 @@ typedef bool _Bool;
|
|||
# define true 1
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
])
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
@ -83,6 +101,8 @@ AH_TEMPLATE([USER_REGS_STRUCT], [Define to structure holding user registers.])
|
|||
AH_TEMPLATE([SYSCALL_NUM_REG], [Define to register holding the system call number.])
|
||||
AH_TEMPLATE([SYSCALL_ARG_REG], [Define to register holding arg0 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG1_REG], [Define to register holding arg1 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG2_REG], [Define to register holding arg2 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_ARG3_REG], [Define to register holding arg3 to system calls.])
|
||||
AH_TEMPLATE([SYSCALL_RET_REG], [Define to register holding value of system calls.])
|
||||
AH_TEMPLATE([STACK_POINTER], [Define to register holding the stack pointer.])
|
||||
AH_TEMPLATE([EXEC_SYSCALL], [Define to number of the `exec' system call.])
|
||||
|
@ -94,6 +114,9 @@ AH_TEMPLATE([EXECUTABLE_BASE], [Virtual address for loading PIC executables])
|
|||
AH_TEMPLATE([INTERPRETER_BASE], [Virtual address for loading PIC interpreters])
|
||||
AH_TEMPLATE([CLONE_SYSCALL], [Define to number of the `clone' system call.])
|
||||
AH_TEMPLATE([CLONE3_SYSCALL], [Define to number of the `clone3' system call.])
|
||||
AH_TEMPLATE([READLINK_SYSCALL], [Define to number of the `readlink' system call.])
|
||||
AH_TEMPLATE([READLINKAT_SYSCALL], [Define to number of the `readlinkat' system call.])
|
||||
AH_TEMPLATE([REENTRANT], [Define to 1 if the library is used within a signal handler.])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
|
@ -206,6 +229,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [rax])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [rdi])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [rsi])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [rdx])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [r10])
|
||||
AC_DEFINE([STACK_POINTER], [rsp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -215,6 +240,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x600000000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code.
|
||||
|
@ -232,6 +259,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [eax])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [ebx])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [ecx])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [edx])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [esi])
|
||||
AC_DEFINE([STACK_POINTER], [esp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -239,6 +268,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0xaf000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code.
|
||||
|
@ -256,6 +287,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [[regs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[regs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[regs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[regs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[regs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [sp])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -264,6 +297,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
# Note that aarch64 has no `readlink'.
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
# Make sure the loader doesn't conflict with other position
|
||||
# dependent code. ARM places rather significant restrictions on
|
||||
|
@ -282,6 +317,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[uregs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -289,6 +326,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||
exec_loader=loader-armeabi.s],
|
||||
|
@ -300,6 +339,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[uregs[0]]])
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[uregs[1]]])
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
|
||||
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -307,6 +348,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
exec_CHECK_LINUX_CLONE3
|
||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||
exec_loader=loader-armeabi.s],
|
||||
|
@ -324,6 +367,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[gregs[5]]]) # a1
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
|
||||
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -331,6 +376,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
AC_CHECK_DECL([_MIPS_SIM], [exec_CHECK_MIPS_NABI],
|
||||
[AC_MSG_ERROR([_MIPS_SIM could not be determined]),
|
||||
[[
|
||||
|
@ -347,6 +394,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([SYSCALL_RET_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG_REG], [[gregs[4]]]) # a0
|
||||
AC_DEFINE([SYSCALL_ARG1_REG], [[gregs[5]]]) # a1
|
||||
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
|
||||
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
|
||||
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
|
||||
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
|
||||
AC_DEFINE([USER_WORD], [uintptr_t])
|
||||
|
@ -355,6 +404,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
|||
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||
AC_CACHE_CHECK([whether as understands `daddi'],
|
||||
[exec_cv_as_daddi],
|
||||
[exec_cv_as_daddi=no
|
||||
|
|
52
exec/exec.c
52
exec/exec.c
|
@ -31,14 +31,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <sys/param.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
||||
#endif /* MAX */
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
#if defined __mips__ && !defined MIPS_NABI
|
||||
|
@ -938,6 +930,10 @@ format_pid (char *in, unsigned int pid)
|
|||
with #!; in that case, find the program to open and use that
|
||||
instead.
|
||||
|
||||
If REENTRANT is not defined, NAME is actually a buffer of size
|
||||
PATH_MAX + 80. In that case, copy over the file name actually
|
||||
opened.
|
||||
|
||||
Next, read the executable header, and add the necessary memory
|
||||
mappings for each file. Finally, return the action data and its
|
||||
size in *SIZE.
|
||||
|
@ -948,7 +944,7 @@ format_pid (char *in, unsigned int pid)
|
|||
Value is NULL upon failure, with errno set accordingly. */
|
||||
|
||||
char *
|
||||
exec_0 (const char *name, struct exec_tracee *tracee,
|
||||
exec_0 (char *name, struct exec_tracee *tracee,
|
||||
size_t *size, USER_REGS_STRUCT *regs)
|
||||
{
|
||||
int fd, rc, i;
|
||||
|
@ -961,7 +957,8 @@ 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;
|
||||
char buffer[80], buffer1[PATH_MAX + 80], *rewrite;
|
||||
ssize_t link_size;
|
||||
size_t remaining;
|
||||
|
||||
/* If name is not absolute, then make it relative to TRACEE's
|
||||
|
@ -971,18 +968,43 @@ exec_0 (const char *name, struct exec_tracee *tracee,
|
|||
{
|
||||
/* Clear `buffer'. */
|
||||
memset (buffer, 0, sizeof buffer);
|
||||
memset (buffer1, 0, sizeof buffer);
|
||||
|
||||
/* Copy over /proc, the PID, and /cwd/. */
|
||||
rewrite = stpcpy (buffer, "/proc/");
|
||||
rewrite = format_pid (rewrite, tracee->pid);
|
||||
rewrite = stpcpy (rewrite, "/cwd/");
|
||||
stpcpy (rewrite, "/cwd");
|
||||
|
||||
/* Make sure there is enough free space. */
|
||||
remaining = buffer + sizeof buffer - rewrite - 1;
|
||||
/* Resolve this symbolic link. */
|
||||
|
||||
link_size = readlink (buffer, buffer1,
|
||||
PATH_MAX + 1);
|
||||
|
||||
if (link_size < 0)
|
||||
return NULL;
|
||||
|
||||
/* Check that the name is a reasonable size. */
|
||||
|
||||
if (link_size > PATH_MAX)
|
||||
{
|
||||
/* The name is too long. */
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add a directory separator if necessary. */
|
||||
|
||||
if (!link_size || buffer1[link_size - 1] != '/')
|
||||
buffer1[link_size] = '/', link_size++;
|
||||
|
||||
rewrite = buffer1 + link_size;
|
||||
remaining = buffer1 + sizeof buffer1 - rewrite - 1;
|
||||
rewrite = stpncpy (rewrite, name, remaining);
|
||||
|
||||
/* Replace name with buffer. */
|
||||
name = buffer;
|
||||
/* Replace name with buffer1. */
|
||||
#ifndef REENTRANT
|
||||
strcpy (name, buffer1);
|
||||
#endif /* REENTRANT */
|
||||
}
|
||||
|
||||
fd = open (name, O_RDONLY);
|
||||
|
|
|
@ -154,6 +154,11 @@ struct exec_tracee
|
|||
/* Whether or not the tracee is currently waiting for a system call
|
||||
to complete. */
|
||||
bool waiting_for_syscall;
|
||||
|
||||
#ifndef REENTRANT
|
||||
/* Name of the executable being run. */
|
||||
char *exec_file;
|
||||
#endif /* !REENTRANT */
|
||||
};
|
||||
|
||||
|
||||
|
@ -184,7 +189,7 @@ extern pid_t exec_waitpid (pid_t, int *, int);
|
|||
|
||||
/* Defined in exec.c. */
|
||||
|
||||
extern char *exec_0 (const char *, struct exec_tracee *,
|
||||
extern char *exec_0 (char *, struct exec_tracee *,
|
||||
size_t *, USER_REGS_STRUCT *);
|
||||
|
||||
|
||||
|
|
168
exec/trace.c
168
exec/trace.c
|
@ -315,6 +315,13 @@ remove_tracee (struct exec_tracee *tracee)
|
|||
|
||||
/* Link the tracee onto the list of free tracees. */
|
||||
tracee->next = free_tracees;
|
||||
|
||||
#ifndef REENTRANT
|
||||
/* Free the exec file, if any. */
|
||||
free (tracee->exec_file);
|
||||
tracee->exec_file = NULL;
|
||||
#endif /* REENTRANT */
|
||||
|
||||
free_tracees = tracee;
|
||||
|
||||
return;
|
||||
|
@ -431,7 +438,7 @@ syscall_trap_p (siginfo_t *signal)
|
|||
static int
|
||||
handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
|
||||
{
|
||||
char buffer[PATH_MAX], *area;
|
||||
char buffer[PATH_MAX + 80], *area;
|
||||
USER_REGS_STRUCT original;
|
||||
size_t size, loader_size;
|
||||
USER_WORD loader, size1, sp;
|
||||
|
@ -517,6 +524,17 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifndef REENTRANT
|
||||
/* Now that the loader has started, record the value to use for
|
||||
/proc/self/exe. Don't give up just because strdup fails.
|
||||
|
||||
Note that exec_0 copies the absolute file name into buffer. */
|
||||
|
||||
if (tracee->exec_file)
|
||||
free (tracee->exec_file);
|
||||
tracee->exec_file = strdup (buffer);
|
||||
#endif /* REENTRANT */
|
||||
|
||||
again:
|
||||
rc = waitpid (tracee->pid, &wstatus, __WALL);
|
||||
if (rc == -1 && errno == EINTR)
|
||||
|
@ -622,6 +640,91 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
|
|||
return 3;
|
||||
}
|
||||
|
||||
/* Handle a `readlink' or `readlinkat' system call.
|
||||
|
||||
CALLNO is the system call number, and REGS are the current user
|
||||
registers of the TRACEE.
|
||||
|
||||
If the first argument of a `readlinkat' system call is AT_FDCWD,
|
||||
and the file name specified in either a `readlink' or `readlinkat'
|
||||
system call is `/proc/self/exe', write the name of the executable
|
||||
being run into the buffer specified in the system call.
|
||||
|
||||
Return the number of bytes written to the tracee's buffer in
|
||||
*RESULT.
|
||||
|
||||
Value is 0 upon success. Value is 1 upon failure, and 2 if the
|
||||
system call has been emulated. */
|
||||
|
||||
static int
|
||||
handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs,
|
||||
struct exec_tracee *tracee, USER_WORD *result)
|
||||
{
|
||||
#ifdef REENTRANT
|
||||
/* readlinkat cannot be handled specially when the library is built
|
||||
to be reentrant, as the file name information cannot be
|
||||
recorded. */
|
||||
return 0;
|
||||
#else /* !REENTRANT */
|
||||
|
||||
char buffer[PATH_MAX + 1];
|
||||
USER_WORD address, return_buffer, size;
|
||||
size_t length;
|
||||
|
||||
/* Read the file name. */
|
||||
|
||||
#ifdef READLINK_SYSCALL
|
||||
if (callno == READLINK_SYSCALL)
|
||||
{
|
||||
address = regs->SYSCALL_ARG_REG;
|
||||
return_buffer = regs->SYSCALL_ARG1_REG;
|
||||
size = regs->SYSCALL_ARG2_REG;
|
||||
}
|
||||
else
|
||||
#endif /* READLINK_SYSCALL */
|
||||
{
|
||||
address = regs->SYSCALL_ARG1_REG;
|
||||
return_buffer = regs->SYSCALL_ARG2_REG;
|
||||
size = regs->SYSCALL_ARG3_REG;
|
||||
}
|
||||
|
||||
read_memory (tracee, buffer, PATH_MAX, address);
|
||||
|
||||
/* Make sure BUFFER is NULL terminated. */
|
||||
|
||||
if (!memchr (buffer, '\0', PATH_MAX))
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Now check if the caller is looking for /proc/self/exe.
|
||||
|
||||
dirfd can be ignored, as for now only absolute file names are
|
||||
handled. FIXME. */
|
||||
|
||||
if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file)
|
||||
return 0;
|
||||
|
||||
/* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or
|
||||
size, whichever is less. */
|
||||
|
||||
length = strlen (tracee->exec_file);
|
||||
length = MIN (size, MIN (PATH_MAX, length));
|
||||
strncpy (buffer, tracee->exec_file, length);
|
||||
|
||||
if (user_copy (tracee, (unsigned char *) buffer,
|
||||
return_buffer, length))
|
||||
{
|
||||
errno = EIO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*result = length;
|
||||
return 2;
|
||||
#endif /* REENTRANT */
|
||||
}
|
||||
|
||||
/* Process the system call at which TRACEE is stopped. If the system
|
||||
call is not known or not exec, send TRACEE on its way. Otherwise,
|
||||
rewrite it to load the loader and perform an appropriate action. */
|
||||
|
@ -635,6 +738,8 @@ process_system_call (struct exec_tracee *tracee)
|
|||
#ifdef __aarch64__
|
||||
USER_WORD old_w1, old_w2;
|
||||
#endif /* __aarch64__ */
|
||||
USER_WORD result;
|
||||
bool reporting_error;
|
||||
|
||||
#ifdef __aarch64__
|
||||
rc = aarch64_get_regs (tracee->pid, ®s);
|
||||
|
@ -678,6 +783,24 @@ process_system_call (struct exec_tracee *tracee)
|
|||
|
||||
break;
|
||||
|
||||
#ifdef READLINK_SYSCALL
|
||||
case READLINK_SYSCALL:
|
||||
#endif /* READLINK_SYSCALL */
|
||||
case READLINKAT_SYSCALL:
|
||||
|
||||
/* Handle this readlinkat system call. */
|
||||
rc = handle_readlinkat (callno, ®s, tracee,
|
||||
&result);
|
||||
|
||||
/* rc means the same as in `handle_exec'. */
|
||||
|
||||
if (rc == 1)
|
||||
goto report_syscall_error;
|
||||
else if (rc == 2)
|
||||
goto emulate_syscall;
|
||||
|
||||
/* Fallthrough. */
|
||||
|
||||
default:
|
||||
/* Don't wait for the system call to finish; instead, the system
|
||||
will DTRT upon the next call to PTRACE_SYSCALL after the
|
||||
|
@ -694,8 +817,16 @@ process_system_call (struct exec_tracee *tracee)
|
|||
return;
|
||||
|
||||
report_syscall_error:
|
||||
/* Reporting an error works by setting the system call number to -1,
|
||||
letting it continue, and then substituting errno for ENOSYS.
|
||||
reporting_error = true;
|
||||
goto common;
|
||||
|
||||
emulate_syscall:
|
||||
reporting_error = false;
|
||||
common:
|
||||
|
||||
/* Reporting an error or emulating a system call works by setting
|
||||
the system call number to -1, letting it continue, and then
|
||||
substituting errno for ENOSYS in the case of an error.
|
||||
|
||||
Make sure that the stack pointer is restored to its original
|
||||
position upon exit, or bad things can happen. */
|
||||
|
@ -755,7 +886,7 @@ process_system_call (struct exec_tracee *tracee)
|
|||
/* The process has been killed in response to a signal. In this
|
||||
case, simply unlink the tracee and return. */
|
||||
remove_tracee (tracee);
|
||||
else
|
||||
else if (reporting_error)
|
||||
{
|
||||
#ifdef __mips__
|
||||
/* MIPS systems place errno in v0 and set a3 to 1. */
|
||||
|
@ -775,6 +906,32 @@ process_system_call (struct exec_tracee *tracee)
|
|||
ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s);
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
/* Now wait for the next system call to happen. */
|
||||
ptrace (PTRACE_SYSCALL, tracee->pid, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No error is being reported. Return the result in the
|
||||
appropriate registers. */
|
||||
|
||||
#ifdef __mips__
|
||||
/* MIPS systems place errno in v0 and set a3 to 1. */
|
||||
regs.gregs[2] = result;
|
||||
regs.gregs[7] = 0;
|
||||
#else /* !__mips__ */
|
||||
regs.SYSCALL_RET_REG = result;
|
||||
#endif /* __mips__ */
|
||||
|
||||
/* Report errno. */
|
||||
#ifdef __aarch64__
|
||||
/* 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);
|
||||
#else /* !__aarch64__ */
|
||||
ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s);
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
/* Now wait for the next system call to happen. */
|
||||
ptrace (PTRACE_SYSCALL, tracee->pid, NULL, NULL);
|
||||
}
|
||||
|
@ -869,6 +1026,9 @@ after_fork (pid_t pid)
|
|||
tracee->pid = pid;
|
||||
tracee->next = tracing_processes;
|
||||
tracee->waiting_for_syscall = false;
|
||||
#ifndef REENTRANT
|
||||
tracee->exec_file = NULL;
|
||||
#endif /* REENTRANT */
|
||||
tracing_processes = tracee;
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue