git: 7e2f38311e62 - main - rtld-elf/rtld.c: apply clang-format

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 21 Jan 2025 01:51:00 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7e2f38311e62b1a3ba4a023042f2dc36e27cdd06

commit 7e2f38311e62b1a3ba4a023042f2dc36e27cdd06
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-01-18 02:26:16 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-01-21 01:44:12 +0000

    rtld-elf/rtld.c: apply clang-format
    
    Discussed with: emaste, imp
    Sponsored by:   The FreeBSD Foundation
    Differential revision:  https://reviews.freebsd.org/D48509
---
 libexec/rtld-elf/rtld.c | 5914 ++++++++++++++++++++++++-----------------------
 1 file changed, 2993 insertions(+), 2921 deletions(-)

diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 70230a8e0199..8ec883227908 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -39,13 +39,13 @@
  */
 
 #include <sys/param.h>
-#include <sys/mount.h>
+#include <sys/ktrace.h>
 #include <sys/mman.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
 #include <sys/uio.h>
 #include <sys/utsname.h>
-#include <sys/ktrace.h>
 
 #include <dlfcn.h>
 #include <err.h>
@@ -58,20 +58,19 @@
 #include <unistd.h>
 
 #include "debug.h"
-#include "rtld.h"
 #include "libmap.h"
+#include "notes.h"
+#include "rtld.h"
+#include "rtld_libc.h"
+#include "rtld_malloc.h"
 #include "rtld_paths.h"
-#include "rtld_tls.h"
 #include "rtld_printf.h"
-#include "rtld_malloc.h"
+#include "rtld_tls.h"
 #include "rtld_utrace.h"
-#include "notes.h"
-#include "rtld_libc.h"
 
 /* Types. */
 typedef void (*func_ptr_type)(void);
-typedef void * (*path_enum_proc) (const char *path, size_t len, void *arg);
-
+typedef void *(*path_enum_proc)(const char *path, size_t len, void *arg);
 
 /* Variables that cannot be static: */
 extern struct r_debug r_debug; /* For GDB */
@@ -138,7 +137,7 @@ static void objlist_put_after(Objlist *, Obj_Entry *, Obj_Entry *);
 static void objlist_remove(Objlist *, Obj_Entry *);
 static int open_binary_fd(const char *argv0, bool search_in_path,
     const char **binpath_res);
-static int parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
+static int parse_args(char *argv[], int argc, bool *use_pathp, int *fdp,
     const char **argv0, bool *dir_ignore);
 static int parse_integer(const char *);
 static void *path_enumerate(const char *, path_enum_proc, const char *, void *);
@@ -174,15 +173,15 @@ static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *, RtldLockState *lockstate);
 static void unref_dag(Obj_Entry *);
 static void ref_dag(Obj_Entry *);
-static char *origin_subst_one(Obj_Entry *, char *, const char *,
-    const char *, bool);
+static char *origin_subst_one(Obj_Entry *, char *, const char *, const char *,
+    bool);
 static char *origin_subst(Obj_Entry *, const char *);
 static bool obj_resolve_origin(Obj_Entry *obj);
 static void preinit_main(void);
-static int  rtld_verify_versions(const Objlist *);
-static int  rtld_verify_object_versions(Obj_Entry *);
+static int rtld_verify_versions(const Objlist *);
+static int rtld_verify_object_versions(Obj_Entry *);
 static void object_add_name(Obj_Entry *, const char *);
-static int  object_match_name(const Obj_Entry *, const char *);
+static int object_match_name(const Obj_Entry *, const char *);
 static void ld_utrace_log(int, void *, void *, size_t, int, const char *);
 static void rtld_fill_dl_phdr_info(const Obj_Entry *obj,
     struct dl_phdr_info *phdr_info);
@@ -198,45 +197,49 @@ int __sys_openat(int, const char *, int, ...);
 /*
  * Data declarations.
  */
-struct r_debug r_debug __exported;	/* for GDB; */
-static bool libmap_disable;	/* Disable libmap */
-static bool ld_loadfltr;	/* Immediate filters processing */
-static const char *libmap_override;/* Maps to use in addition to libmap.conf */
-static bool trust;		/* False for setuid and setgid programs */
-static bool dangerous_ld_env;	/* True if environment variables have been
-				   used to affect the libraries loaded */
-bool ld_bind_not;		/* Disable PLT update */
-static const char *ld_bind_now;	/* Environment variable for immediate binding */
+struct r_debug r_debug __exported;  /* for GDB; */
+static bool libmap_disable;	    /* Disable libmap */
+static bool ld_loadfltr;	    /* Immediate filters processing */
+static const char *libmap_override; /* Maps to use in addition to libmap.conf */
+static bool trust;		    /* False for setuid and setgid programs */
+static bool dangerous_ld_env;	    /* True if environment variables have been
+				       used to affect the libraries loaded */
+bool ld_bind_not;		    /* Disable PLT update */
+static const char *ld_bind_now; /* Environment variable for immediate binding */
 static const char *ld_debug;	/* Environment variable for debugging */
 static bool ld_dynamic_weak = true; /* True if non-weak definition overrides
 				       weak definition */
-static const char *ld_library_path;/* Environment variable for search path */
-static const char *ld_library_dirs;/* Environment variable for library descriptors */
-static const char *ld_preload;	/* Environment variable for libraries to
-				   load first */
-static const char *ld_preload_fds;/* Environment variable for libraries represented by
-				   descriptors */
-static const char *ld_elf_hints_path;	/* Environment variable for alternative hints path */
-static const char *ld_tracing;	/* Called from ldd to print libs */
-static const char *ld_utrace;	/* Use utrace() to log events. */
-static struct obj_entry_q obj_list;	/* Queue of all loaded objects */
-static Obj_Entry *obj_main;	/* The main program shared object */
-static Obj_Entry obj_rtld;	/* The dynamic linker shared object */
-static unsigned int obj_count;	/* Number of objects in obj_list */
-static unsigned int obj_loads;	/* Number of loads of objects (gen count) */
-size_t ld_static_tls_extra =	/* Static TLS extra space (bytes) */
-  RTLD_STATIC_TLS_EXTRA;
-
-static Objlist list_global =	/* Objects dlopened with RTLD_GLOBAL */
-  STAILQ_HEAD_INITIALIZER(list_global);
-static Objlist list_main =	/* Objects loaded at program startup */
-  STAILQ_HEAD_INITIALIZER(list_main);
-static Objlist list_fini =	/* Objects needing fini() calls */
-  STAILQ_HEAD_INITIALIZER(list_fini);
-
-Elf_Sym sym_zero;		/* For resolving undefined weak refs. */
-
-#define GDB_STATE(s,m)	r_debug.r_state = s; r_debug_state(&r_debug,m);
+static const char *ld_library_path; /* Environment variable for search path */
+static const char
+    *ld_library_dirs; /* Environment variable for library descriptors */
+static const char *ld_preload;	   /* Environment variable for libraries to
+				      load first */
+static const char *ld_preload_fds; /* Environment variable for libraries
+				    represented by descriptors */
+static const char
+    *ld_elf_hints_path; /* Environment variable for alternative hints path */
+static const char *ld_tracing;	    /* Called from ldd to print libs */
+static const char *ld_utrace;	    /* Use utrace() to log events. */
+static struct obj_entry_q obj_list; /* Queue of all loaded objects */
+static Obj_Entry *obj_main;	    /* The main program shared object */
+static Obj_Entry obj_rtld;	    /* The dynamic linker shared object */
+static unsigned int obj_count;	    /* Number of objects in obj_list */
+static unsigned int obj_loads;	    /* Number of loads of objects (gen count) */
+size_t ld_static_tls_extra =	    /* Static TLS extra space (bytes) */
+    RTLD_STATIC_TLS_EXTRA;
+
+static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */
+    STAILQ_HEAD_INITIALIZER(list_global);
+static Objlist list_main = /* Objects loaded at program startup */
+    STAILQ_HEAD_INITIALIZER(list_main);
+static Objlist list_fini = /* Objects needing fini() calls */
+    STAILQ_HEAD_INITIALIZER(list_fini);
+
+Elf_Sym sym_zero; /* For resolving undefined weak refs. */
+
+#define GDB_STATE(s, m)      \
+	r_debug.r_state = s; \
+	r_debug_state(&r_debug, m);
 
 extern Elf_Dyn _DYNAMIC;
 #pragma weak _DYNAMIC
@@ -251,7 +254,7 @@ void *dlvsym(void *, const char *, const char *) __exported;
 int dladdr(const void *, Dl_info *) __exported;
 void dllockinit(void *, void *(*)(void *), void (*)(void *), void (*)(void *),
     void (*)(void *), void (*)(void *), void (*)(void *)) __exported;
-int dlinfo(void *, int , void *) __exported;
+int dlinfo(void *, int, void *) __exported;
 int _dl_iterate_phdr_locked(__dl_iterate_hdr_callback, void *) __exported;
 int dl_iterate_phdr(__dl_iterate_hdr_callback, void *) __exported;
 int _rtld_addr_phdr(const void *, struct dl_phdr_info *) __exported;
@@ -290,12 +293,12 @@ char **main_argv;
 /*
  * Globals to control TLS allocation.
  */
-size_t tls_last_offset;		/* Static TLS offset of last module */
-size_t tls_last_size;		/* Static TLS size of last module */
-size_t tls_static_space;	/* Static TLS space allocated */
+size_t tls_last_offset;	 /* Static TLS offset of last module */
+size_t tls_last_size;	 /* Static TLS size of last module */
+size_t tls_static_space; /* Static TLS space allocated */
 static size_t tls_static_max_align;
-Elf_Addr tls_dtv_generation = 1;	/* Used to detect when dtv size changes */
-int tls_max_index = 1;		/* Largest module index allocated */
+Elf_Addr tls_dtv_generation = 1; /* Used to detect when dtv size changes */
+int tls_max_index = 1;		 /* Largest module index allocated */
 
 static bool ld_library_path_rpath = false;
 bool ld_fast_sigblock = false;
@@ -316,16 +319,16 @@ static void (*rtld_exit_ptr)(void);
  * the currently-loaded objects.  Keep this as a macro since it calls
  * alloca and we want that to occur within the scope of the caller.
  */
-#define donelist_init(dlp)					\
-    ((dlp)->objs = alloca(obj_count * sizeof (dlp)->objs[0]),	\
-    assert((dlp)->objs != NULL),				\
-    (dlp)->num_alloc = obj_count,				\
-    (dlp)->num_used = 0)
+#define donelist_init(dlp)                                             \
+	((dlp)->objs = alloca(obj_count * sizeof(dlp)->objs[0]),       \
+	    assert((dlp)->objs != NULL), (dlp)->num_alloc = obj_count, \
+	    (dlp)->num_used = 0)
 
-#define	LD_UTRACE(e, h, mb, ms, r, n) do {			\
-	if (ld_utrace != NULL)					\
-		ld_utrace_log(e, h, mb, ms, r, n);		\
-} while (0)
+#define LD_UTRACE(e, h, mb, ms, r, n)                      \
+	do {                                               \
+		if (ld_utrace != NULL)                     \
+			ld_utrace_log(e, h, mb, ms, r, n); \
+	} while (0)
 
 static void
 ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
@@ -347,19 +350,15 @@ ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
 }
 
 struct ld_env_var_desc {
-	const char * const n;
+	const char *const n;
 	const char *val;
-	const bool unsecure:1;
-	const bool can_update:1;
-	const bool debug:1;
-	bool owned:1;
+	const bool unsecure : 1;
+	const bool can_update : 1;
+	const bool debug : 1;
+	bool owned : 1;
 };
-#define LD_ENV_DESC(var, unsec, ...)		\
-	[LD_##var] = {				\
-	    .n = #var,				\
-	    .unsecure = unsec,			\
-	    __VA_ARGS__				\
-	}
+#define LD_ENV_DESC(var, unsec, ...) \
+	[LD_##var] = { .n = #var, .unsecure = unsec, __VA_ARGS__ }
 
 static struct ld_env_var_desc ld_env_vars[] = {
 	LD_ENV_DESC(BIND_NOW, false),
@@ -494,506 +493,524 @@ rtld_trunc_page(uintptr_t x)
 func_ptr_type
 _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 {
-    Elf_Auxinfo *aux, *auxp, *auxpf, *aux_info[AT_COUNT];
-    Objlist_Entry *entry;
-    Obj_Entry *last_interposer, *obj, *preload_tail;
-    const Elf_Phdr *phdr;
-    Objlist initlist;
-    RtldLockState lockstate;
-    struct stat st;
-    Elf_Addr *argcp;
-    char **argv, **env, **envp, *kexecpath;
-    const char *argv0, *binpath, *library_path_rpath, *static_tls_extra;
-    struct ld_env_var_desc *lvd;
-    caddr_t imgentry;
-    char buf[MAXPATHLEN];
-    int argc, fd, i, mib[4], old_osrel, osrel, phnum, rtld_argc;
-    size_t sz;
+	Elf_Auxinfo *aux, *auxp, *auxpf, *aux_info[AT_COUNT];
+	Objlist_Entry *entry;
+	Obj_Entry *last_interposer, *obj, *preload_tail;
+	const Elf_Phdr *phdr;
+	Objlist initlist;
+	RtldLockState lockstate;
+	struct stat st;
+	Elf_Addr *argcp;
+	char **argv, **env, **envp, *kexecpath;
+	const char *argv0, *binpath, *library_path_rpath, *static_tls_extra;
+	struct ld_env_var_desc *lvd;
+	caddr_t imgentry;
+	char buf[MAXPATHLEN];
+	int argc, fd, i, mib[4], old_osrel, osrel, phnum, rtld_argc;
+	size_t sz;
 #ifdef __powerpc__
-    int old_auxv_format = 1;
+	int old_auxv_format = 1;
 #endif
-    bool dir_enable, dir_ignore, direct_exec, explicit_fd, search_in_path;
-
-    /*
-     * On entry, the dynamic linker itself has not been relocated yet.
-     * Be very careful not to reference any global data until after
-     * init_rtld has returned.  It is OK to reference file-scope statics
-     * and string constants, and to call static and global functions.
-     */
-
-    /* Find the auxiliary vector on the stack. */
-    argcp = sp;
-    argc = *sp++;
-    argv = (char **) sp;
-    sp += argc + 1;	/* Skip over arguments and NULL terminator */
-    env = (char **) sp;
-    while (*sp++ != 0)	/* Skip over environment, and NULL terminator */
-	;
-    aux = (Elf_Auxinfo *) sp;
-
-    /* Digest the auxiliary vector. */
-    for (i = 0;  i < AT_COUNT;  i++)
-	aux_info[i] = NULL;
-    for (auxp = aux;  auxp->a_type != AT_NULL;  auxp++) {
-	if (auxp->a_type < AT_COUNT)
-	    aux_info[auxp->a_type] = auxp;
+	bool dir_enable, dir_ignore, direct_exec, explicit_fd, search_in_path;
+
+	/*
+	 * On entry, the dynamic linker itself has not been relocated yet.
+	 * Be very careful not to reference any global data until after
+	 * init_rtld has returned.  It is OK to reference file-scope statics
+	 * and string constants, and to call static and global functions.
+	 */
+
+	/* Find the auxiliary vector on the stack. */
+	argcp = sp;
+	argc = *sp++;
+	argv = (char **)sp;
+	sp += argc + 1; /* Skip over arguments and NULL terminator */
+	env = (char **)sp;
+	while (*sp++ != 0) /* Skip over environment, and NULL terminator */
+		;
+	aux = (Elf_Auxinfo *)sp;
+
+	/* Digest the auxiliary vector. */
+	for (i = 0; i < AT_COUNT; i++)
+		aux_info[i] = NULL;
+	for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
+		if (auxp->a_type < AT_COUNT)
+			aux_info[auxp->a_type] = auxp;
 #ifdef __powerpc__
-	if (auxp->a_type == 23) /* AT_STACKPROT */
-	    old_auxv_format = 0;
+		if (auxp->a_type == 23) /* AT_STACKPROT */
+			old_auxv_format = 0;
 #endif
-    }
+	}
 
 #ifdef __powerpc__
-    if (old_auxv_format) {
-	/* Remap from old-style auxv numbers. */
-	aux_info[23] = aux_info[21];	/* AT_STACKPROT */
-	aux_info[21] = aux_info[19];	/* AT_PAGESIZESLEN */
-	aux_info[19] = aux_info[17];	/* AT_NCPUS */
-	aux_info[17] = aux_info[15];	/* AT_CANARYLEN */
-	aux_info[15] = aux_info[13];	/* AT_EXECPATH */
-	aux_info[13] = NULL;		/* AT_GID */
-
-	aux_info[20] = aux_info[18];	/* AT_PAGESIZES */
-	aux_info[18] = aux_info[16];	/* AT_OSRELDATE */
-	aux_info[16] = aux_info[14];	/* AT_CANARY */
-	aux_info[14] = NULL;		/* AT_EGID */
-    }
+	if (old_auxv_format) {
+		/* Remap from old-style auxv numbers. */
+		aux_info[23] = aux_info[21]; /* AT_STACKPROT */
+		aux_info[21] = aux_info[19]; /* AT_PAGESIZESLEN */
+		aux_info[19] = aux_info[17]; /* AT_NCPUS */
+		aux_info[17] = aux_info[15]; /* AT_CANARYLEN */
+		aux_info[15] = aux_info[13]; /* AT_EXECPATH */
+		aux_info[13] = NULL;	     /* AT_GID */
+
+		aux_info[20] = aux_info[18]; /* AT_PAGESIZES */
+		aux_info[18] = aux_info[16]; /* AT_OSRELDATE */
+		aux_info[16] = aux_info[14]; /* AT_CANARY */
+		aux_info[14] = NULL;	     /* AT_EGID */
+	}
 #endif
 
-    /* Initialize and relocate ourselves. */
-    assert(aux_info[AT_BASE] != NULL);
-    init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr, aux_info);
-
-    dlerror_dflt_init();
-
-    __progname = obj_rtld.path;
-    argv0 = argv[0] != NULL ? argv[0] : "(null)";
-    environ = env;
-    main_argc = argc;
-    main_argv = argv;
-
-    if (aux_info[AT_BSDFLAGS] != NULL &&
-	(aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)
-	    ld_fast_sigblock = true;
-
-    trust = !issetugid();
-    direct_exec = false;
-
-    md_abi_variant_hook(aux_info);
-    rtld_init_env_vars(env);
-
-    fd = -1;
-    if (aux_info[AT_EXECFD] != NULL) {
-	fd = aux_info[AT_EXECFD]->a_un.a_val;
-    } else {
-	assert(aux_info[AT_PHDR] != NULL);
-	phdr = (const Elf_Phdr *)aux_info[AT_PHDR]->a_un.a_ptr;
-	if (phdr == obj_rtld.phdr) {
-	    if (!trust) {
-		_rtld_error("Tainted process refusing to run binary %s",
-		    argv0);
-		rtld_die();
-	    }
-	    direct_exec = true;
-
-	    dbg("opening main program in direct exec mode");
-	    if (argc >= 2) {
-		rtld_argc = parse_args(argv, argc, &search_in_path, &fd,
-		  &argv0, &dir_ignore);
-		explicit_fd = (fd != -1);
-		binpath = NULL;
-		if (!explicit_fd)
-		    fd = open_binary_fd(argv0, search_in_path, &binpath);
-		if (fstat(fd, &st) == -1) {
-		    _rtld_error("Failed to fstat FD %d (%s): %s", fd,
-		      explicit_fd ? "user-provided descriptor" : argv0,
-		      rtld_strerror(errno));
-		    rtld_die();
-		}
+	/* Initialize and relocate ourselves. */
+	assert(aux_info[AT_BASE] != NULL);
+	init_rtld((caddr_t)aux_info[AT_BASE]->a_un.a_ptr, aux_info);
 
-		/*
-		 * Rough emulation of the permission checks done by
-		 * execve(2), only Unix DACs are checked, ACLs are
-		 * ignored.  Preserve the semantic of disabling owner
-		 * to execute if owner x bit is cleared, even if
-		 * others x bit is enabled.
-		 * mmap(2) does not allow to mmap with PROT_EXEC if
-		 * binary' file comes from noexec mount.  We cannot
-		 * set a text reference on the binary.
-		 */
-		dir_enable = false;
-		if (st.st_uid == geteuid()) {
-		    if ((st.st_mode & S_IXUSR) != 0)
-			dir_enable = true;
-		} else if (st.st_gid == getegid()) {
-		    if ((st.st_mode & S_IXGRP) != 0)
-			dir_enable = true;
-		} else if ((st.st_mode & S_IXOTH) != 0) {
-		    dir_enable = true;
-		}
-		if (!dir_enable && !dir_ignore) {
-		    _rtld_error("No execute permission for binary %s",
-		        argv0);
-		    rtld_die();
-		}
+	dlerror_dflt_init();
 
-		/*
-		 * For direct exec mode, argv[0] is the interpreter
-		 * name, we must remove it and shift arguments left
-		 * before invoking binary main.  Since stack layout
-		 * places environment pointers and aux vectors right
-		 * after the terminating NULL, we must shift
-		 * environment and aux as well.
-		 */
-		main_argc = argc - rtld_argc;
-		for (i = 0; i <= main_argc; i++)
-		    argv[i] = argv[i + rtld_argc];
-		*argcp -= rtld_argc;
-		environ = env = envp = argv + main_argc + 1;
-		dbg("move env from %p to %p", envp + rtld_argc, envp);
-		do {
-		    *envp = *(envp + rtld_argc);
-		}  while (*envp++ != NULL);
-		aux = auxp = (Elf_Auxinfo *)envp;
-		auxpf = (Elf_Auxinfo *)(envp + rtld_argc);
-		dbg("move aux from %p to %p", auxpf, aux);
-		/* XXXKIB insert place for AT_EXECPATH if not present */
-		for (;; auxp++, auxpf++) {
-		    *auxp = *auxpf;
-		    if (auxp->a_type == AT_NULL)
-			    break;
-		}
-		/* Since the auxiliary vector has moved, redigest it. */
-		for (i = 0;  i < AT_COUNT;  i++)
-		    aux_info[i] = NULL;
-		for (auxp = aux;  auxp->a_type != AT_NULL;  auxp++) {
-		    if (auxp->a_type < AT_COUNT)
-			aux_info[auxp->a_type] = auxp;
+	__progname = obj_rtld.path;
+	argv0 = argv[0] != NULL ? argv[0] : "(null)";
+	environ = env;
+	main_argc = argc;
+	main_argv = argv;
+
+	if (aux_info[AT_BSDFLAGS] != NULL &&
+	    (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)
+		ld_fast_sigblock = true;
+
+	trust = !issetugid();
+	direct_exec = false;
+
+	md_abi_variant_hook(aux_info);
+	rtld_init_env_vars(env);
+
+	fd = -1;
+	if (aux_info[AT_EXECFD] != NULL) {
+		fd = aux_info[AT_EXECFD]->a_un.a_val;
+	} else {
+		assert(aux_info[AT_PHDR] != NULL);
+		phdr = (const Elf_Phdr *)aux_info[AT_PHDR]->a_un.a_ptr;
+		if (phdr == obj_rtld.phdr) {
+			if (!trust) {
+				_rtld_error(
+				    "Tainted process refusing to run binary %s",
+				    argv0);
+				rtld_die();
+			}
+			direct_exec = true;
+
+			dbg("opening main program in direct exec mode");
+			if (argc >= 2) {
+				rtld_argc = parse_args(argv, argc,
+				    &search_in_path, &fd, &argv0, &dir_ignore);
+				explicit_fd = (fd != -1);
+				binpath = NULL;
+				if (!explicit_fd)
+					fd = open_binary_fd(argv0,
+					    search_in_path, &binpath);
+				if (fstat(fd, &st) == -1) {
+					_rtld_error(
+					    "Failed to fstat FD %d (%s): %s",
+					    fd,
+					    explicit_fd ?
+						"user-provided descriptor" :
+						argv0,
+					    rtld_strerror(errno));
+					rtld_die();
+				}
+
+				/*
+				 * Rough emulation of the permission checks done
+				 * by execve(2), only Unix DACs are checked,
+				 * ACLs are ignored.  Preserve the semantic of
+				 * disabling owner to execute if owner x bit is
+				 * cleared, even if others x bit is enabled.
+				 * mmap(2) does not allow to mmap with PROT_EXEC
+				 * if binary' file comes from noexec mount.  We
+				 * cannot set a text reference on the binary.
+				 */
+				dir_enable = false;
+				if (st.st_uid == geteuid()) {
+					if ((st.st_mode & S_IXUSR) != 0)
+						dir_enable = true;
+				} else if (st.st_gid == getegid()) {
+					if ((st.st_mode & S_IXGRP) != 0)
+						dir_enable = true;
+				} else if ((st.st_mode & S_IXOTH) != 0) {
+					dir_enable = true;
+				}
+				if (!dir_enable && !dir_ignore) {
+					_rtld_error(
+				    "No execute permission for binary %s",
+					    argv0);
+					rtld_die();
+				}
+
+				/*
+				 * For direct exec mode, argv[0] is the
+				 * interpreter name, we must remove it and shift
+				 * arguments left before invoking binary main.
+				 * Since stack layout places environment
+				 * pointers and aux vectors right after the
+				 * terminating NULL, we must shift environment
+				 * and aux as well.
+				 */
+				main_argc = argc - rtld_argc;
+				for (i = 0; i <= main_argc; i++)
+					argv[i] = argv[i + rtld_argc];
+				*argcp -= rtld_argc;
+				environ = env = envp = argv + main_argc + 1;
+				dbg("move env from %p to %p", envp + rtld_argc,
+				    envp);
+				do {
+					*envp = *(envp + rtld_argc);
+				} while (*envp++ != NULL);
+				aux = auxp = (Elf_Auxinfo *)envp;
+				auxpf = (Elf_Auxinfo *)(envp + rtld_argc);
+				dbg("move aux from %p to %p", auxpf, aux);
+				/* XXXKIB insert place for AT_EXECPATH if not
+				 * present */
+				for (;; auxp++, auxpf++) {
+					*auxp = *auxpf;
+					if (auxp->a_type == AT_NULL)
+						break;
+				}
+				/* Since the auxiliary vector has moved,
+				 * redigest it. */
+				for (i = 0; i < AT_COUNT; i++)
+					aux_info[i] = NULL;
+				for (auxp = aux; auxp->a_type != AT_NULL;
+				    auxp++) {
+					if (auxp->a_type < AT_COUNT)
+						aux_info[auxp->a_type] = auxp;
+				}
+
+				/* Point AT_EXECPATH auxv and aux_info to the
+				 * binary path. */
+				if (binpath == NULL) {
+					aux_info[AT_EXECPATH] = NULL;
+				} else {
+					if (aux_info[AT_EXECPATH] == NULL) {
+						aux_info[AT_EXECPATH] = xmalloc(
+						    sizeof(Elf_Auxinfo));
+						aux_info[AT_EXECPATH]->a_type =
+						    AT_EXECPATH;
+					}
+					aux_info[AT_EXECPATH]->a_un.a_ptr =
+					    __DECONST(void *, binpath);
+				}
+			} else {
+				_rtld_error("No binary");
+				rtld_die();
+			}
 		}
+	}
 
-		/* Point AT_EXECPATH auxv and aux_info to the binary path. */
-		if (binpath == NULL) {
-		    aux_info[AT_EXECPATH] = NULL;
-		} else {
-		    if (aux_info[AT_EXECPATH] == NULL) {
-			aux_info[AT_EXECPATH] = xmalloc(sizeof(Elf_Auxinfo));
-			aux_info[AT_EXECPATH]->a_type = AT_EXECPATH;
-		    }
-		    aux_info[AT_EXECPATH]->a_un.a_ptr = __DECONST(void *,
-		      binpath);
+	ld_bind_now = ld_get_env_var(LD_BIND_NOW);
+
+	/*
+	 * If the process is tainted, then we un-set the dangerous environment
+	 * variables.  The process will be marked as tainted until setuid(2)
+	 * is called.  If any child process calls setuid(2) we do not want any
+	 * future processes to honor the potentially un-safe variables.
+	 */
+	if (!trust) {
+		for (i = 0; i < (int)nitems(ld_env_vars); i++) {
+			lvd = &ld_env_vars[i];
+			if (lvd->unsecure)
+				lvd->val = NULL;
 		}
-	    } else {
-		_rtld_error("No binary");
-		rtld_die();
-	    }
-	}
-    }
-
-    ld_bind_now = ld_get_env_var(LD_BIND_NOW);
-
-    /*
-     * If the process is tainted, then we un-set the dangerous environment
-     * variables.  The process will be marked as tainted until setuid(2)
-     * is called.  If any child process calls setuid(2) we do not want any
-     * future processes to honor the potentially un-safe variables.
-     */
-    if (!trust) {
-	    for (i = 0; i < (int)nitems(ld_env_vars); i++) {
-		    lvd = &ld_env_vars[i];
-		    if (lvd->unsecure)
-			    lvd->val = NULL;
-	    }
-    }
-
-    ld_debug = ld_get_env_var(LD_DEBUG);
-    if (ld_bind_now == NULL)
-	    ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
-    ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) == NULL;
-    libmap_disable = ld_get_env_var(LD_LIBMAP_DISABLE) != NULL;
-    libmap_override = ld_get_env_var(LD_LIBMAP);
-    ld_library_path = ld_get_env_var(LD_LIBRARY_PATH);
-    ld_library_dirs = ld_get_env_var(LD_LIBRARY_PATH_FDS);
-    ld_preload = ld_get_env_var(LD_PRELOAD);
-    ld_preload_fds = ld_get_env_var(LD_PRELOAD_FDS);
-    ld_elf_hints_path = ld_get_env_var(LD_ELF_HINTS_PATH);
-    ld_loadfltr = ld_get_env_var(LD_LOADFLTR) != NULL;
-    library_path_rpath = ld_get_env_var(LD_LIBRARY_PATH_RPATH);
-    if (library_path_rpath != NULL) {
-	    if (library_path_rpath[0] == 'y' ||
-		library_path_rpath[0] == 'Y' ||
-		library_path_rpath[0] == '1')
-		    ld_library_path_rpath = true;
-	    else
-		    ld_library_path_rpath = false;
-    }
-    static_tls_extra = ld_get_env_var(LD_STATIC_TLS_EXTRA);
-    if (static_tls_extra != NULL && static_tls_extra[0] != '\0') {
-	sz = parse_integer(static_tls_extra);
-	if (sz >= RTLD_STATIC_TLS_EXTRA && sz <= SIZE_T_MAX)
-	    ld_static_tls_extra = sz;
-    }
-    dangerous_ld_env = libmap_disable || libmap_override != NULL ||
-	ld_library_path != NULL || ld_preload != NULL ||
-	ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak ||
-	static_tls_extra != NULL;
-    ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS);
-    ld_utrace = ld_get_env_var(LD_UTRACE);
-
-    set_ld_elf_hints_path();
-    if (ld_debug != NULL && *ld_debug != '\0')
-	debug = 1;
-    dbg("%s is initialized, base address = %p", __progname,
-	(caddr_t) aux_info[AT_BASE]->a_un.a_ptr);
-    dbg("RTLD dynamic = %p", obj_rtld.dynamic);
-    dbg("RTLD pltgot  = %p", obj_rtld.pltgot);
-
-    dbg("initializing thread locks");
-    lockdflt_init();
-
-    /*
-     * Load the main program, or process its program header if it is
-     * already loaded.
-     */
-    if (fd != -1) {	/* Load the main program. */
-	dbg("loading main program");
-	obj_main = map_object(fd, argv0, NULL);
-	close(fd);
-	if (obj_main == NULL)
-	    rtld_die();
-	max_stack_flags = obj_main->stack_flags;
-    } else {				/* Main program already loaded. */
-	dbg("processing main program's program header");
-	assert(aux_info[AT_PHDR] != NULL);
-	phdr = (const Elf_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr;
-	assert(aux_info[AT_PHNUM] != NULL);
-	phnum = aux_info[AT_PHNUM]->a_un.a_val;
-	assert(aux_info[AT_PHENT] != NULL);
-	assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr));
-	assert(aux_info[AT_ENTRY] != NULL);
-	imgentry = (caddr_t) aux_info[AT_ENTRY]->a_un.a_ptr;
-	if ((obj_main = digest_phdr(phdr, phnum, imgentry, argv0)) == NULL)
-	    rtld_die();
-    }
-
-    if (aux_info[AT_EXECPATH] != NULL && fd == -1) {
-	    kexecpath = aux_info[AT_EXECPATH]->a_un.a_ptr;
-	    dbg("AT_EXECPATH %p %s", kexecpath, kexecpath);
-	    if (kexecpath[0] == '/')
-		    obj_main->path = kexecpath;
-	    else if (getcwd(buf, sizeof(buf)) == NULL ||
-		     strlcat(buf, "/", sizeof(buf)) >= sizeof(buf) ||
-		     strlcat(buf, kexecpath, sizeof(buf)) >= sizeof(buf))
-		    obj_main->path = xstrdup(argv0);
-	    else
-		    obj_main->path = xstrdup(buf);
-    } else {
-	    dbg("No AT_EXECPATH or direct exec");
-	    obj_main->path = xstrdup(argv0);
-    }
-    dbg("obj_main path %s", obj_main->path);
-    obj_main->mainprog = true;
-
-    if (aux_info[AT_STACKPROT] != NULL &&
-      aux_info[AT_STACKPROT]->a_un.a_val != 0)
-	    stack_prot = aux_info[AT_STACKPROT]->a_un.a_val;
+	}
+
+	ld_debug = ld_get_env_var(LD_DEBUG);
+	if (ld_bind_now == NULL)
+		ld_bind_not = ld_get_env_var(LD_BIND_NOT) != NULL;
+	ld_dynamic_weak = ld_get_env_var(LD_DYNAMIC_WEAK) == NULL;
+	libmap_disable = ld_get_env_var(LD_LIBMAP_DISABLE) != NULL;
+	libmap_override = ld_get_env_var(LD_LIBMAP);
+	ld_library_path = ld_get_env_var(LD_LIBRARY_PATH);
+	ld_library_dirs = ld_get_env_var(LD_LIBRARY_PATH_FDS);
+	ld_preload = ld_get_env_var(LD_PRELOAD);
+	ld_preload_fds = ld_get_env_var(LD_PRELOAD_FDS);
+	ld_elf_hints_path = ld_get_env_var(LD_ELF_HINTS_PATH);
+	ld_loadfltr = ld_get_env_var(LD_LOADFLTR) != NULL;
+	library_path_rpath = ld_get_env_var(LD_LIBRARY_PATH_RPATH);
+	if (library_path_rpath != NULL) {
+		if (library_path_rpath[0] == 'y' ||
+		    library_path_rpath[0] == 'Y' ||
+		    library_path_rpath[0] == '1')
+			ld_library_path_rpath = true;
+		else
+			ld_library_path_rpath = false;
+	}
+	static_tls_extra = ld_get_env_var(LD_STATIC_TLS_EXTRA);
+	if (static_tls_extra != NULL && static_tls_extra[0] != '\0') {
+		sz = parse_integer(static_tls_extra);
+		if (sz >= RTLD_STATIC_TLS_EXTRA && sz <= SIZE_T_MAX)
+			ld_static_tls_extra = sz;
+	}
+	dangerous_ld_env = libmap_disable || libmap_override != NULL ||
+	    ld_library_path != NULL || ld_preload != NULL ||
+	    ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak ||
+	    static_tls_extra != NULL;
+	ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS);
+	ld_utrace = ld_get_env_var(LD_UTRACE);
+
+	set_ld_elf_hints_path();
+	if (ld_debug != NULL && *ld_debug != '\0')
+		debug = 1;
+	dbg("%s is initialized, base address = %p", __progname,
+	    (caddr_t)aux_info[AT_BASE]->a_un.a_ptr);
+	dbg("RTLD dynamic = %p", obj_rtld.dynamic);
+	dbg("RTLD pltgot  = %p", obj_rtld.pltgot);
+
+	dbg("initializing thread locks");
+	lockdflt_init();
+
+	/*
+	 * Load the main program, or process its program header if it is
+	 * already loaded.
+	 */
+	if (fd != -1) { /* Load the main program. */
+		dbg("loading main program");
+		obj_main = map_object(fd, argv0, NULL);
+		close(fd);
+		if (obj_main == NULL)
+			rtld_die();
+		max_stack_flags = obj_main->stack_flags;
+	} else { /* Main program already loaded. */
+		dbg("processing main program's program header");
+		assert(aux_info[AT_PHDR] != NULL);
+		phdr = (const Elf_Phdr *)aux_info[AT_PHDR]->a_un.a_ptr;
+		assert(aux_info[AT_PHNUM] != NULL);
+		phnum = aux_info[AT_PHNUM]->a_un.a_val;
+		assert(aux_info[AT_PHENT] != NULL);
+		assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr));
+		assert(aux_info[AT_ENTRY] != NULL);
+		imgentry = (caddr_t)aux_info[AT_ENTRY]->a_un.a_ptr;
+		if ((obj_main = digest_phdr(phdr, phnum, imgentry, argv0)) ==
+		    NULL)
+			rtld_die();
+	}
+
+	if (aux_info[AT_EXECPATH] != NULL && fd == -1) {
+		kexecpath = aux_info[AT_EXECPATH]->a_un.a_ptr;
+		dbg("AT_EXECPATH %p %s", kexecpath, kexecpath);
+		if (kexecpath[0] == '/')
+			obj_main->path = kexecpath;
+		else if (getcwd(buf, sizeof(buf)) == NULL ||
+		    strlcat(buf, "/", sizeof(buf)) >= sizeof(buf) ||
+		    strlcat(buf, kexecpath, sizeof(buf)) >= sizeof(buf))
+			obj_main->path = xstrdup(argv0);
+		else
+			obj_main->path = xstrdup(buf);
+	} else {
+		dbg("No AT_EXECPATH or direct exec");
+		obj_main->path = xstrdup(argv0);
+	}
+	dbg("obj_main path %s", obj_main->path);
+	obj_main->mainprog = true;
+
+	if (aux_info[AT_STACKPROT] != NULL &&
+	    aux_info[AT_STACKPROT]->a_un.a_val != 0)
+		stack_prot = aux_info[AT_STACKPROT]->a_un.a_val;
 
 #ifndef COMPAT_libcompat
-    /*
-     * Get the actual dynamic linker pathname from the executable if
-     * possible.  (It should always be possible.)  That ensures that
-     * gdb will find the right dynamic linker even if a non-standard
-     * one is being used.
-     */
-    if (obj_main->interp != NULL &&
-      strcmp(obj_main->interp, obj_rtld.path) != 0) {
-	free(obj_rtld.path);
-	obj_rtld.path = xstrdup(obj_main->interp);
-        __progname = obj_rtld.path;
-    }
+	/*
+	 * Get the actual dynamic linker pathname from the executable if
+	 * possible.  (It should always be possible.)  That ensures that
+	 * gdb will find the right dynamic linker even if a non-standard
+	 * one is being used.
+	 */
+	if (obj_main->interp != NULL &&
+	    strcmp(obj_main->interp, obj_rtld.path) != 0) {
+		free(obj_rtld.path);
+		obj_rtld.path = xstrdup(obj_main->interp);
+		__progname = obj_rtld.path;
+	}
 #endif
 
-    if (!digest_dynamic(obj_main, 0))
-	rtld_die();
-    dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d",
-	obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu,
-	obj_main->dynsymcount);
-
-    linkmap_add(obj_main);
-    linkmap_add(&obj_rtld);
-
-    /* Link the main program into the list of objects. */
-    TAILQ_INSERT_HEAD(&obj_list, obj_main, next);
-    obj_count++;
-    obj_loads++;
-
-    /* Initialize a fake symbol for resolving undefined weak references. */
-    sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
-    sym_zero.st_shndx = SHN_UNDEF;
-    sym_zero.st_value = -(uintptr_t)obj_main->relocbase;
-
-    if (!libmap_disable)
-        libmap_disable = (bool)lm_init(libmap_override);
-
-    if (aux_info[AT_KPRELOAD] != NULL &&
-      aux_info[AT_KPRELOAD]->a_un.a_ptr != NULL) {
-	dbg("loading kernel vdso");
-	if (load_kpreload(aux_info[AT_KPRELOAD]->a_un.a_ptr) == -1)
-	    rtld_die();
-    }
-
-    dbg("loading LD_PRELOAD_FDS libraries");
-    if (load_preload_objects(ld_preload_fds, true) == -1)
-	rtld_die();
+	if (!digest_dynamic(obj_main, 0))
+		rtld_die();
+	dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d",
+	    obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu,
+	    obj_main->dynsymcount);
 
-    dbg("loading LD_PRELOAD libraries");
-    if (load_preload_objects(ld_preload, false) == -1)
-	rtld_die();
-    preload_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q));
+	linkmap_add(obj_main);
+	linkmap_add(&obj_rtld);
 
-    dbg("loading needed objects");
-    if (load_needed_objects(obj_main, ld_tracing != NULL ? RTLD_LO_TRACE :
-      0) == -1)
-	rtld_die();
+	/* Link the main program into the list of objects. */
+	TAILQ_INSERT_HEAD(&obj_list, obj_main, next);
+	obj_count++;
+	obj_loads++;
 
-    /* Make a list of all objects loaded at startup. */
-    last_interposer = obj_main;
-    TAILQ_FOREACH(obj, &obj_list, next) {
-	if (obj->marker)
-	    continue;
-	if (obj->z_interpose && obj != obj_main) {
-	    objlist_put_after(&list_main, last_interposer, obj);
-	    last_interposer = obj;
-	} else {
-	    objlist_push_tail(&list_main, obj);
+	/* Initialize a fake symbol for resolving undefined weak references. */
+	sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
+	sym_zero.st_shndx = SHN_UNDEF;
+	sym_zero.st_value = -(uintptr_t)obj_main->relocbase;
+
+	if (!libmap_disable)
+		libmap_disable = (bool)lm_init(libmap_override);
+
+	if (aux_info[AT_KPRELOAD] != NULL &&
+	    aux_info[AT_KPRELOAD]->a_un.a_ptr != NULL) {
+		dbg("loading kernel vdso");
+		if (load_kpreload(aux_info[AT_KPRELOAD]->a_un.a_ptr) == -1)
+			rtld_die();
 	}
-    	obj->refcount++;
-    }
 
-    dbg("checking for required versions");
-    if (rtld_verify_versions(&list_main) == -1 && !ld_tracing)
-	rtld_die();
+	dbg("loading LD_PRELOAD_FDS libraries");
+	if (load_preload_objects(ld_preload_fds, true) == -1)
*** 6242 LINES SKIPPED ***