b1dca6
commit 2bf9e641fd50ec34b04b70829679abf64fc0ed78
b1dca6
Author: Florian Weimer <fweimer@redhat.com>
b1dca6
Date:   Thu Oct 8 10:57:09 2020 +0200
b1dca6
b1dca6
    elf: Extract command-line/environment variables state from rtld.c
b1dca6
    
b1dca6
    Introduce struct dl_main_state and move it to <dl-main.h>.  Rename
b1dca6
    enum mode to enum rtld_mode and add the rtld_mode_ prefix to the enum
b1dca6
    constants.
b1dca6
    
b1dca6
    This avoids the need for putting state that is only needed during
b1dca6
    startup into the ld.so data segment.
b1dca6
b1dca6
Conflicts:
b1dca6
	elf/rtld.c
b1dca6
	  (Caused by glibc-fedora-__libc_multiple_libcs.patch.)
b1dca6
b1dca6
diff --git a/elf/dl-main.h b/elf/dl-main.h
b1dca6
new file mode 100644
b1dca6
index 0000000000000000..bcc9bcf2e8fee6e7
b1dca6
--- /dev/null
b1dca6
+++ b/elf/dl-main.h
b1dca6
@@ -0,0 +1,98 @@
b1dca6
+/* Information collection during ld.so startup.
b1dca6
+   Copyright (C) 1995-2020 Free Software Foundation, Inc.
b1dca6
+   This file is part of the GNU C Library.
b1dca6
+
b1dca6
+   The GNU C Library is free software; you can redistribute it and/or
b1dca6
+   modify it under the terms of the GNU Lesser General Public
b1dca6
+   License as published by the Free Software Foundation; either
b1dca6
+   version 2.1 of the License, or (at your option) any later version.
b1dca6
+
b1dca6
+   The GNU C Library is distributed in the hope that it will be useful,
b1dca6
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
b1dca6
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
b1dca6
+   Lesser General Public License for more details.
b1dca6
+
b1dca6
+   You should have received a copy of the GNU Lesser General Public
b1dca6
+   License along with the GNU C Library; if not, see
b1dca6
+   <https://www.gnu.org/licenses/>.  */
b1dca6
+
b1dca6
+#ifndef _DL_MAIN
b1dca6
+#define _DL_MAIN
b1dca6
+
b1dca6
+#include <limits.h>
b1dca6
+
b1dca6
+/* Length limits for names and paths, to protect the dynamic linker,
b1dca6
+   particularly when __libc_enable_secure is active.  */
b1dca6
+#ifdef NAME_MAX
b1dca6
+# define SECURE_NAME_LIMIT NAME_MAX
b1dca6
+#else
b1dca6
+# define SECURE_NAME_LIMIT 255
b1dca6
+#endif
b1dca6
+#ifdef PATH_MAX
b1dca6
+# define SECURE_PATH_LIMIT PATH_MAX
b1dca6
+#else
b1dca6
+# define SECURE_PATH_LIMIT 1024
b1dca6
+#endif
b1dca6
+
b1dca6
+/* Strings containing colon-separated lists of audit modules.  */
b1dca6
+struct audit_list
b1dca6
+{
b1dca6
+  /* Array of strings containing colon-separated path lists.  Each
b1dca6
+     audit module needs its own namespace, so pre-allocate the largest
b1dca6
+     possible list.  */
b1dca6
+  const char *audit_strings[DL_NNS];
b1dca6
+
b1dca6
+  /* Number of entries added to audit_strings.  */
b1dca6
+  size_t length;
b1dca6
+
b1dca6
+  /* Index into the audit_strings array (for the iteration phase).  */
b1dca6
+  size_t current_index;
b1dca6
+
b1dca6
+  /* Tail of audit_strings[current_index] which still needs
b1dca6
+     processing.  */
b1dca6
+  const char *current_tail;
b1dca6
+
b1dca6
+  /* Scratch buffer for returning a name which is part of the strings
b1dca6
+     in audit_strings.  */
b1dca6
+  char fname[SECURE_NAME_LIMIT];
b1dca6
+};
b1dca6
+
b1dca6
+/* This is a list of all the modes the dynamic loader can be in.  */
b1dca6
+enum rtld_mode
b1dca6
+  {
b1dca6
+    rtld_mode_normal, rtld_mode_list, rtld_mode_verify, rtld_mode_trace,
b1dca6
+  };
b1dca6
+
b1dca6
+/* Aggregated state information extracted from environment variables
b1dca6
+   and the ld.so command line.  */
b1dca6
+struct dl_main_state
b1dca6
+{
b1dca6
+  struct audit_list audit_list;
b1dca6
+
b1dca6
+  /* The library search path.  */
b1dca6
+  const char *library_path;
b1dca6
+
b1dca6
+  /* The list preloaded objects from LD_PRELOAD.  */
b1dca6
+  const char *preloadlist;
b1dca6
+
b1dca6
+  /* The preload list passed as a command argument.  */
b1dca6
+  const char *preloadarg;
b1dca6
+
b1dca6
+  enum rtld_mode mode;
b1dca6
+
b1dca6
+  /* True if any of the debugging options is enabled.  */
b1dca6
+  bool any_debug;
b1dca6
+
b1dca6
+  /* True if information about versions has to be printed.  */
b1dca6
+  bool version_info;
b1dca6
+};
b1dca6
+
b1dca6
+/* Helper function to invoke _dl_init_paths with the right arguments
b1dca6
+   from *STATE.  */
b1dca6
+static inline void
b1dca6
+call_init_paths (const struct dl_main_state *state)
b1dca6
+{
b1dca6
+  _dl_init_paths (state->library_path);
b1dca6
+}
b1dca6
+
b1dca6
+#endif /* _DL_MAIN */
b1dca6
diff --git a/elf/rtld.c b/elf/rtld.c
b1dca6
index 4107a215abd554f4..fbfa441bf3b050ff 100644
b1dca6
--- a/elf/rtld.c
b1dca6
+++ b/elf/rtld.c
b1dca6
@@ -45,6 +45,7 @@
b1dca6
 #include <not-cancel.h>
b1dca6
 #include <array_length.h>
b1dca6
 #include <libc-early-init.h>
b1dca6
+#include <dl-main.h>
b1dca6
 
b1dca6
 #include <assert.h>
b1dca6
 
b1dca6
@@ -109,42 +110,6 @@ static void print_missing_version (int errcode, const char *objname,
b1dca6
 /* Print the various times we collected.  */
b1dca6
 static void print_statistics (const hp_timing_t *total_timep);
b1dca6
 
b1dca6
-/* Length limits for names and paths, to protect the dynamic linker,
b1dca6
-   particularly when __libc_enable_secure is active.  */
b1dca6
-#ifdef NAME_MAX
b1dca6
-# define SECURE_NAME_LIMIT NAME_MAX
b1dca6
-#else
b1dca6
-# define SECURE_NAME_LIMIT 255
b1dca6
-#endif
b1dca6
-#ifdef PATH_MAX
b1dca6
-# define SECURE_PATH_LIMIT PATH_MAX
b1dca6
-#else
b1dca6
-# define SECURE_PATH_LIMIT 1024
b1dca6
-#endif
b1dca6
-
b1dca6
-/* Strings containing colon-separated lists of audit modules.  */
b1dca6
-struct audit_list
b1dca6
-{
b1dca6
-  /* Array of strings containing colon-separated path lists.  Each
b1dca6
-     audit module needs its own namespace, so pre-allocate the largest
b1dca6
-     possible list.  */
b1dca6
-  const char *audit_strings[DL_NNS];
b1dca6
-
b1dca6
-  /* Number of entries added to audit_strings.  */
b1dca6
-  size_t length;
b1dca6
-
b1dca6
-  /* Index into the audit_strings array (for the iteration phase).  */
b1dca6
-  size_t current_index;
b1dca6
-
b1dca6
-  /* Tail of audit_strings[current_index] which still needs
b1dca6
-     processing.  */
b1dca6
-  const char *current_tail;
b1dca6
-
b1dca6
-  /* Scratch buffer for returning a name which is part of the strings
b1dca6
-     in audit_strings.  */
b1dca6
-  char fname[SECURE_NAME_LIMIT];
b1dca6
-};
b1dca6
-
b1dca6
 /* Creates an empty audit list.  */
b1dca6
 static void audit_list_init (struct audit_list *);
b1dca6
 
b1dca6
@@ -165,13 +130,13 @@ static void audit_list_add_dynamic_tag (struct audit_list *,
b1dca6
    audit_list_add_dynamic_tags calls.  */
b1dca6
 static const char *audit_list_next (struct audit_list *);
b1dca6
 
b1dca6
-/* This is a list of all the modes the dynamic loader can be in.  */
b1dca6
-enum mode { normal, list, verify, trace };
b1dca6
+/* Initialize *STATE with the defaults.  */
b1dca6
+static void dl_main_state_init (struct dl_main_state *state);
b1dca6
 
b1dca6
 /* Process all environments variables the dynamic linker must recognize.
b1dca6
    Since all of them start with `LD_' we are a bit smarter while finding
b1dca6
    all the entries.  */
b1dca6
-static void process_envvars (enum mode *modep, struct audit_list *);
b1dca6
+static void process_envvars (struct dl_main_state *state);
b1dca6
 
b1dca6
 #ifdef DL_ARGV_NOT_RELRO
b1dca6
 int _dl_argc attribute_hidden;
b1dca6
@@ -314,6 +279,18 @@ audit_list_count (struct audit_list *list)
b1dca6
   return naudit;
b1dca6
 }
b1dca6
 
b1dca6
+static void
b1dca6
+dl_main_state_init (struct dl_main_state *state)
b1dca6
+{
b1dca6
+  audit_list_init (&state->audit_list);
b1dca6
+  state->library_path = NULL;
b1dca6
+  state->preloadlist = NULL;
b1dca6
+  state->preloadarg = NULL;
b1dca6
+  state->mode = rtld_mode_normal;
b1dca6
+  state->any_debug = false;
b1dca6
+  state->version_info = false;
b1dca6
+}
b1dca6
+
b1dca6
 /* Set nonzero during loading and initialization of executable and
b1dca6
    libraries, cleared before the executable's entry point runs.  This
b1dca6
    must not be initialized to nonzero, because the unused dynamic
b1dca6
@@ -896,15 +873,6 @@ security_init (void)
b1dca6
 
b1dca6
 #include "setup-vdso.h"
b1dca6
 
b1dca6
-/* The library search path.  */
b1dca6
-static const char *library_path attribute_relro;
b1dca6
-/* The list preloaded objects.  */
b1dca6
-static const char *preloadlist attribute_relro;
b1dca6
-/* Nonzero if information about versions has to be printed.  */
b1dca6
-static int version_info attribute_relro;
b1dca6
-/* The preload list passed as a command argument.  */
b1dca6
-static const char *preloadarg attribute_relro;
b1dca6
-
b1dca6
 /* The LD_PRELOAD environment variable gives list of libraries
b1dca6
    separated by white space or colons that are loaded before the
b1dca6
    executable's dependencies and prepended to the global scope list.
b1dca6
@@ -1146,7 +1114,6 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
 	 ElfW(auxv_t) *auxv)
b1dca6
 {
b1dca6
   const ElfW(Phdr) *ph;
b1dca6
-  enum mode mode;
b1dca6
   struct link_map *main_map;
b1dca6
   size_t file_size;
b1dca6
   char *file;
b1dca6
@@ -1156,8 +1123,8 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
   bool rtld_is_main = false;
b1dca6
   void *tcbp = NULL;
b1dca6
 
b1dca6
-  struct audit_list audit_list;
b1dca6
-  audit_list_init (&audit_list);
b1dca6
+  struct dl_main_state state;
b1dca6
+  dl_main_state_init (&state);
b1dca6
 
b1dca6
   GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
b1dca6
 
b1dca6
@@ -1172,7 +1139,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
   GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
b1dca6
 
b1dca6
   /* Process the environment variable which control the behaviour.  */
b1dca6
-  process_envvars (&mode, &audit_list);
b1dca6
+  process_envvars (&state);
b1dca6
 
b1dca6
   /* Set up a flag which tells we are just starting.  */
b1dca6
   _dl_starting_up = 1;
b1dca6
@@ -1204,7 +1171,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
       while (_dl_argc > 1)
b1dca6
 	if (! strcmp (_dl_argv[1], "--list"))
b1dca6
 	  {
b1dca6
-	    mode = list;
b1dca6
+	    state.mode = rtld_mode_list;
b1dca6
 	    GLRO(dl_lazy) = -1;	/* This means do no dependency analysis.  */
b1dca6
 
b1dca6
 	    ++_dl_skip_args;
b1dca6
@@ -1213,7 +1180,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
 	  }
b1dca6
 	else if (! strcmp (_dl_argv[1], "--verify"))
b1dca6
 	  {
b1dca6
-	    mode = verify;
b1dca6
+	    state.mode = rtld_mode_verify;
b1dca6
 
b1dca6
 	    ++_dl_skip_args;
b1dca6
 	    --_dl_argc;
b1dca6
@@ -1229,7 +1196,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
 	else if (! strcmp (_dl_argv[1], "--library-path")
b1dca6
 		 && _dl_argc > 2)
b1dca6
 	  {
b1dca6
-	    library_path = _dl_argv[2];
b1dca6
+	    state.library_path = _dl_argv[2];
b1dca6
 
b1dca6
 	    _dl_skip_args += 2;
b1dca6
 	    _dl_argc -= 2;
b1dca6
@@ -1246,7 +1213,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
 	  }
b1dca6
 	else if (! strcmp (_dl_argv[1], "--audit") && _dl_argc > 2)
b1dca6
 	  {
b1dca6
-	    audit_list_add_string (&audit_list, _dl_argv[2]);
b1dca6
+	    audit_list_add_string (&state.audit_list, _dl_argv[2]);
b1dca6
 
b1dca6
 	    _dl_skip_args += 2;
b1dca6
 	    _dl_argc -= 2;
b1dca6
@@ -1254,7 +1221,7 @@ dl_main (const ElfW(Phdr) *phdr,
b1dca6
 	  }
b1dca6
 	else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
b1dca6
 	  {
b1dca6
-	    preloadarg = _dl_argv[2];
b1dca6
+	    state.preloadarg = _dl_argv[2];
b1dca6
 	    _dl_skip_args += 2;
b1dca6
 	    _dl_argc -= 2;
b1dca6
 	    _dl_argv += 2;
b1dca6
@@ -1322,7 +1289,7 @@ of this helper program; chances are you did not intend to run this program.\n\
b1dca6
 	    break;
b1dca6
 	  }
b1dca6
 
b1dca6
-      if (__builtin_expect (mode, normal) == verify)
b1dca6
+      if (__glibc_unlikely (state.mode == rtld_mode_verify))
b1dca6
 	{
b1dca6
 	  const char *objname;
b1dca6
 	  const char *err_str = NULL;
b1dca6
@@ -1351,7 +1318,7 @@ of this helper program; chances are you did not intend to run this program.\n\
b1dca6
       /* Now the map for the main executable is available.  */
b1dca6
       main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
b1dca6
 
b1dca6
-      if (__builtin_expect (mode, normal) == normal
b1dca6
+      if (__glibc_likely (state.mode == rtld_mode_normal)
b1dca6
 	  && GL(dl_rtld_map).l_info[DT_SONAME] != NULL
b1dca6
 	  && main_map->l_info[DT_SONAME] != NULL
b1dca6
 	  && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
b1dca6
@@ -1592,7 +1559,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
       _dl_setup_hash (main_map);
b1dca6
     }
b1dca6
 
b1dca6
-  if (__builtin_expect (mode, normal) == verify)
b1dca6
+  if (__glibc_unlikely (state.mode == rtld_mode_verify))
b1dca6
     {
b1dca6
       /* We were called just to verify that this is a dynamic
b1dca6
 	 executable using us as the program interpreter.  Exit with an
b1dca6
@@ -1619,7 +1586,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
 
b1dca6
   /* Initialize the data structures for the search paths for shared
b1dca6
      objects.  */
b1dca6
-  _dl_init_paths (library_path);
b1dca6
+  call_init_paths (&state);
b1dca6
 
b1dca6
   /* Initialize _r_debug.  */
b1dca6
   struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
b1dca6
@@ -1684,14 +1651,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
     /* Assign a module ID.  Do this before loading any audit modules.  */
b1dca6
     GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
b1dca6
 
b1dca6
-  audit_list_add_dynamic_tag (&audit_list, main_map, DT_AUDIT);
b1dca6
-  audit_list_add_dynamic_tag (&audit_list, main_map, DT_DEPAUDIT);
b1dca6
+  audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT);
b1dca6
+  audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT);
b1dca6
 
b1dca6
   /* If we have auditing DSOs to load, do it now.  */
b1dca6
   bool need_security_init = true;
b1dca6
-  if (audit_list.length > 0)
b1dca6
+  if (state.audit_list.length > 0)
b1dca6
     {
b1dca6
-      size_t naudit = audit_list_count (&audit_list);
b1dca6
+      size_t naudit = audit_list_count (&state.audit_list);
b1dca6
 
b1dca6
       /* Since we start using the auditing DSOs right away we need to
b1dca6
 	 initialize the data structures now.  */
b1dca6
@@ -1704,7 +1671,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
       security_init ();
b1dca6
       need_security_init = false;
b1dca6
 
b1dca6
-      load_audit_modules (main_map, &audit_list);
b1dca6
+      load_audit_modules (main_map, &state.audit_list);
b1dca6
 
b1dca6
       /* The count based on audit strings may overestimate the number
b1dca6
 	 of audit modules that got loaded, but not underestimate.  */
b1dca6
@@ -1759,19 +1726,21 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
   struct link_map **preloads = NULL;
b1dca6
   unsigned int npreloads = 0;
b1dca6
 
b1dca6
-  if (__glibc_unlikely (preloadlist != NULL))
b1dca6
+  if (__glibc_unlikely (state.preloadlist != NULL))
b1dca6
     {
b1dca6
       RTLD_TIMING_VAR (start);
b1dca6
       rtld_timer_start (&start;;
b1dca6
-      npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD");
b1dca6
+      npreloads += handle_preload_list (state.preloadlist, main_map,
b1dca6
+					"LD_PRELOAD");
b1dca6
       rtld_timer_accum (&load_time, start);
b1dca6
     }
b1dca6
 
b1dca6
-  if (__glibc_unlikely (preloadarg != NULL))
b1dca6
+  if (__glibc_unlikely (state.preloadarg != NULL))
b1dca6
     {
b1dca6
       RTLD_TIMING_VAR (start);
b1dca6
       rtld_timer_start (&start;;
b1dca6
-      npreloads += handle_preload_list (preloadarg, main_map, "--preload");
b1dca6
+      npreloads += handle_preload_list (state.preloadarg, main_map,
b1dca6
+					"--preload");
b1dca6
       rtld_timer_accum (&load_time, start);
b1dca6
     }
b1dca6
 
b1dca6
@@ -1878,7 +1847,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
   {
b1dca6
     RTLD_TIMING_VAR (start);
b1dca6
     rtld_timer_start (&start;;
b1dca6
-    _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
b1dca6
+    _dl_map_object_deps (main_map, preloads, npreloads,
b1dca6
+			 state.mode == rtld_mode_trace, 0);
b1dca6
     rtld_timer_accum (&load_time, start);
b1dca6
   }
b1dca6
 
b1dca6
@@ -1905,7 +1875,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
       rtld_multiple_ref = true;
b1dca6
 
b1dca6
       GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
b1dca6
-      if (__builtin_expect (mode, normal) == normal)
b1dca6
+      if (__glibc_likely (state.mode == rtld_mode_normal))
b1dca6
 	{
b1dca6
 	  GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
b1dca6
 				    ? main_map->l_searchlist.r_list[i + 1]
b1dca6
@@ -1938,8 +1908,8 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
      versions we need.  */
b1dca6
   {
b1dca6
     struct version_check_args args;
b1dca6
-    args.doexit = mode == normal;
b1dca6
-    args.dotrace = mode == trace;
b1dca6
+    args.doexit = state.mode == rtld_mode_normal;
b1dca6
+    args.dotrace = state.mode == rtld_mode_trace;
b1dca6
     _dl_receive_error (print_missing_version, version_check_doit, &args);
b1dca6
   }
b1dca6
 
b1dca6
@@ -1959,7 +1929,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
        earlier.  */
b1dca6
     security_init ();
b1dca6
 
b1dca6
-  if (__builtin_expect (mode, normal) != normal)
b1dca6
+  if (__glibc_unlikely (state.mode != rtld_mode_normal))
b1dca6
     {
b1dca6
       /* We were run just to list the shared libraries.  It is
b1dca6
 	 important that we do this before real relocation, because the
b1dca6
@@ -2061,7 +2031,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
 			  (size_t) l->l_map_start);
b1dca6
 	}
b1dca6
 
b1dca6
-      if (__builtin_expect (mode, trace) != trace)
b1dca6
+      if (__glibc_unlikely (state.mode != rtld_mode_trace))
b1dca6
 	for (i = 1; i < (unsigned int) _dl_argc; ++i)
b1dca6
 	  {
b1dca6
 	    const ElfW(Sym) *ref = NULL;
b1dca6
@@ -2115,7 +2085,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
b1dca6
 		}
b1dca6
 	    }
b1dca6
 #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
b1dca6
-	  if (version_info)
b1dca6
+	  if (state.version_info)
b1dca6
 	    {
b1dca6
 	      /* Print more information.  This means here, print information
b1dca6
 		 about the versions needed.  */
b1dca6
@@ -2477,13 +2447,10 @@ print_missing_version (int errcode __attribute__ ((unused)),
b1dca6
 		    objname, errstring);
b1dca6
 }
b1dca6
 
b1dca6
-/* Nonzero if any of the debugging options is enabled.  */
b1dca6
-static int any_debug attribute_relro;
b1dca6
-
b1dca6
 /* Process the string given as the parameter which explains which debugging
b1dca6
    options are enabled.  */
b1dca6
 static void
b1dca6
-process_dl_debug (const char *dl_debug)
b1dca6
+process_dl_debug (struct dl_main_state *state, const char *dl_debug)
b1dca6
 {
b1dca6
   /* When adding new entries make sure that the maximal length of a name
b1dca6
      is correctly handled in the LD_DEBUG_HELP code below.  */
b1dca6
@@ -2540,7 +2507,7 @@ process_dl_debug (const char *dl_debug)
b1dca6
 		&& memcmp (dl_debug, debopts[cnt].name, len) == 0)
b1dca6
 	      {
b1dca6
 		GLRO(dl_debug_mask) |= debopts[cnt].mask;
b1dca6
-		any_debug = 1;
b1dca6
+		state->any_debug = true;
b1dca6
 		break;
b1dca6
 	      }
b1dca6
 
b1dca6
@@ -2594,11 +2561,10 @@ extern char **_environ attribute_hidden;
b1dca6
 
b1dca6
 
b1dca6
 static void
b1dca6
-process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
+process_envvars (struct dl_main_state *state)
b1dca6
 {
b1dca6
   char **runp = _environ;
b1dca6
   char *envline;
b1dca6
-  enum mode mode = normal;
b1dca6
   char *debug_output = NULL;
b1dca6
 
b1dca6
   /* This is the default place for profiling data file.  */
b1dca6
@@ -2630,25 +2596,25 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	  /* Debugging of the dynamic linker?  */
b1dca6
 	  if (memcmp (envline, "DEBUG", 5) == 0)
b1dca6
 	    {
b1dca6
-	      process_dl_debug (&envline[6]);
b1dca6
+	      process_dl_debug (state, &envline[6]);
b1dca6
 	      break;
b1dca6
 	    }
b1dca6
 	  if (memcmp (envline, "AUDIT", 5) == 0)
b1dca6
-	    audit_list_add_string (audit_list, &envline[6]);
b1dca6
+	    audit_list_add_string (&state->audit_list, &envline[6]);
b1dca6
 	  break;
b1dca6
 
b1dca6
 	case 7:
b1dca6
 	  /* Print information about versions.  */
b1dca6
 	  if (memcmp (envline, "VERBOSE", 7) == 0)
b1dca6
 	    {
b1dca6
-	      version_info = envline[8] != '\0';
b1dca6
+	      state->version_info = envline[8] != '\0';
b1dca6
 	      break;
b1dca6
 	    }
b1dca6
 
b1dca6
 	  /* List of objects to be preloaded.  */
b1dca6
 	  if (memcmp (envline, "PRELOAD", 7) == 0)
b1dca6
 	    {
b1dca6
-	      preloadlist = &envline[8];
b1dca6
+	      state->preloadlist = &envline[8];
b1dca6
 	      break;
b1dca6
 	    }
b1dca6
 
b1dca6
@@ -2697,7 +2663,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	  if (!__libc_enable_secure
b1dca6
 	      && memcmp (envline, "LIBRARY_PATH", 12) == 0)
b1dca6
 	    {
b1dca6
-	      library_path = &envline[13];
b1dca6
+	      state->library_path = &envline[13];
b1dca6
 	      break;
b1dca6
 	    }
b1dca6
 
b1dca6
@@ -2739,7 +2705,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	  /* The mode of the dynamic linker can be set.  */
b1dca6
 	  if (memcmp (envline, "TRACE_PRELINKING", 16) == 0)
b1dca6
 	    {
b1dca6
-	      mode = trace;
b1dca6
+	      state->mode = rtld_mode_trace;
b1dca6
 	      GLRO(dl_verbose) = 1;
b1dca6
 	      GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
b1dca6
 	      GLRO(dl_trace_prelink) = &envline[17];
b1dca6
@@ -2749,7 +2715,7 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	case 20:
b1dca6
 	  /* The mode of the dynamic linker can be set.  */
b1dca6
 	  if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)
b1dca6
-	    mode = trace;
b1dca6
+	    state->mode = rtld_mode_trace;
b1dca6
 	  break;
b1dca6
 
b1dca6
 	  /* We might have some extra environment variable to handle.  This
b1dca6
@@ -2762,9 +2728,6 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	}
b1dca6
     }
b1dca6
 
b1dca6
-  /* The caller wants this information.  */
b1dca6
-  *modep = mode;
b1dca6
-
b1dca6
   /* Extra security for SUID binaries.  Remove all dangerous environment
b1dca6
      variables.  */
b1dca6
   if (__builtin_expect (__libc_enable_secure, 0))
b1dca6
@@ -2793,13 +2756,13 @@ process_envvars (enum mode *modep, struct audit_list *audit_list)
b1dca6
 	  GLRO(dl_debug_mask) = 0;
b1dca6
 	}
b1dca6
 
b1dca6
-      if (mode != normal)
b1dca6
+      if (state->mode != rtld_mode_normal)
b1dca6
 	_exit (5);
b1dca6
     }
b1dca6
   /* If we have to run the dynamic linker in debugging mode and the
b1dca6
      LD_DEBUG_OUTPUT environment variable is given, we write the debug
b1dca6
      messages to this file.  */
b1dca6
-  else if (any_debug && debug_output != NULL)
b1dca6
+  else if (state->any_debug && debug_output != NULL)
b1dca6
     {
b1dca6
       const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW;
b1dca6
       size_t name_len = strlen (debug_output);