summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog32
-rw-r--r--elf/dl-deps.c7
-rw-r--r--elf/dl-fini.c4
-rw-r--r--elf/dl-init.c2
-rw-r--r--elf/dl-load.c64
-rw-r--r--elf/dl-lookup.c10
-rw-r--r--elf/dl-misc.c52
-rw-r--r--elf/dl-reloc.c4
-rw-r--r--elf/dl-support.c3
-rw-r--r--elf/dl-version.c6
-rw-r--r--elf/link.h10
-rw-r--r--elf/rtld.c46
-rw-r--r--libc.map1
-rw-r--r--posix/wordexp-test.c19
-rw-r--r--sysdeps/unix/sysv/linux/libc-start.c6
-rw-r--r--sysdeps/unix/sysv/linux/sys/quota.h162
16 files changed, 388 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 54421bfae3..010408a31f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,37 @@
+1998-03-10 17:54  Ulrich Drepper  <drepper@cygnus.com>
+
+	* libc.map: Add _dl_debug_message.
+	* elf/dl-misc.c: Make _dl_debug_message a function.  Print the PID
+	before every line.
+	* elf/fini.c: Correctly use new _dl_debug_message function.
+	* elf/init.c: Likewise.
+	* elf/dl-lookup.c: Likewise.
+	* sysdeps/unix/sysv/linux/libc-start.c: Likewise.
+	* elf/dl-load.c: Likewise.  Add more debugging prints.
+	* elf/dl-reloc.c: Likewise.
+	* elf/dl-version.c: Likewise.
+	* elf/dl-support.c: Add variables for debugging.
+	* elf/rtld.c: Likewise.  Recognize new debug options.
+	* elf/link.h: Declare new variables.
+
+	* elf/dl-deps.c (_dl_map_object_deps): Little optimizations.
+
 1998-03-10  Ulrich Drepper  <drepper@cygnus.com>
 
+	* sysdeps/unix/sysv/linux/sys/quota.h: Extract information from
+	kernel headers.  Patch by a sun <asun@saul7.u.washington.edu>.
+
+1998-03-11 00:16  Tim Waugh  <tim@cyberelk.demon.co.uk>
+
+	* posix/wordexp-test.c (command_line_test): New function to allow
+	testing of specific cases from the command-line.
+
+1998-03-10  Ulrich Drepper  <drepper@cygnus.com>
+
+	* elf/dl-init.c (_dl_init_next): Print nicer messages.
+	* elf/dl-fini.c (_dl_fini): Likewise.
+	* sysdeps/unix/sysv/linux/libc-start.c (__libc_start_main): Likewise.
+
 	* elf/dl-lookup.c (_dl_lookup_versioned_symbol): Print version
 	symbol in debug message.
 	(_dl_lookup_versioned_symbol_skip): Likewise.
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index c069fab0c8..76e71d78cb 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -139,7 +139,7 @@ _dl_map_object_deps (struct link_map *map,
     {
       struct link_map *l = runp->map;
 
-      if (l->l_info[AUXTAG] || l->l_info[FILTERTAG] || l->l_info[DT_NEEDED])
+      if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
 	{
 	  const char *strtab = ((void *) l->l_addr
 				+ l->l_info[DT_STRTAB]->d_un.d_ptr);
@@ -228,12 +228,11 @@ _dl_map_object_deps (struct link_map *map,
 		newp = alloca (sizeof (struct list));
 
 		/* Copy the content of the current entry over.  */
-		memcpy (newp, orig, sizeof (*newp));
+		orig->dup = memcpy (newp, orig, sizeof (*newp));
 
 		/* Initialize new entry.  */
 		orig->done = 0;
 		orig->map = args.aux;
-		orig->dup = newp;
 
 		/* We must handle two situations here: the map is new,
 		   so we must add it in all three lists.  If the map
@@ -347,7 +346,7 @@ _dl_map_object_deps (struct link_map *map,
       if (runp->done)
 	do
 	  runp = runp->unique;
-	while (runp && runp->done);
+	while (runp != NULL && runp->done);
     }
 
   /* Store the search list we built in the object.  It will be used for
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 9dcd87ad11..abbd8c878e 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -32,9 +32,9 @@ _dl_fini (void)
 	  {
 	    /* When debugging print a message first.  */
 	    if (_dl_debug_impcalls)
-	      _dl_debug_message ("\n\tcalling fini: ",
+	      _dl_debug_message (1, "\ncalling fini: ",
 				 l->l_name[0] ? l->l_name : _dl_argv[0],
-				 "\n", NULL);
+				 "\n\n", NULL);
 
 	    (*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
 	  }
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 6fcac75a60..6bdad4e841 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -60,7 +60,7 @@ _dl_init_next (struct link_map *map)
 
 	  /* Print a debug message if wanted.  */
 	  if (_dl_debug_impcalls)
-	    _dl_debug_message ("\tcalling init: ",
+	    _dl_debug_message (1, "\ncalling init: ",
 				l->l_name[0] ? l->l_name : _dl_argv[0],
 				"\n\n", NULL);
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 1d700f9da4..06c8ad57b4 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -28,6 +28,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include "dynamic-link.h"
+#include <stdio-common/_itoa.h>
 
 
 /* On some systems, no flag bits are given to specify file mapping.  */
@@ -527,6 +528,7 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
   const ElfW(Ehdr) *header;
   const ElfW(Phdr) *phdr;
   const ElfW(Phdr) *ph;
+  size_t maplength;
   int type;
 
   /* Look again to see if the real name matched another already loaded.  */
@@ -545,6 +547,10 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
 	return l;
       }
 
+  /* Print debugging message.  */
+  if (_dl_debug_files)
+    _dl_debug_message (1, "file=", name, ";  generating link map\n", NULL);
+
   /* Map in the first page to read the header.  */
   header = map (0, sizeof *header);
 
@@ -663,6 +669,9 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
     /* Now process the load commands and map segments into memory.  */
     c = loadcmds;
 
+    /* Length of the sections to be loaded.  */
+    maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
+
     if (type == ET_DYN || type == ET_REL)
       {
 	/* This is a position-independent shared object.  We can let the
@@ -678,7 +687,6 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
 	   the OS can do whatever it likes. */
  	caddr_t mapat;
 	ElfW(Addr) mappref;
-	size_t maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
 	mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart)
 		   - MAP_BASE_ADDR (l));
 	mapat = map_segment (mappref, maplength, c->prot, 0, c->mapoff);
@@ -786,6 +794,36 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
 
   l->l_entry += l->l_addr;
 
+  if (_dl_debug_files)
+    {
+      const size_t nibbles = sizeof (void *) * 2;
+      char buf1[nibbles + 1];
+      char buf2[nibbles + 1];
+      char buf3[nibbles + 1];
+
+      buf1[nibbles] = '\0';
+      buf2[nibbles] = '\0';
+      buf3[nibbles] = '\0';
+
+      memset (buf1, '0', nibbles);
+      memset (buf2, '0', nibbles);
+      memset (buf3, '0', nibbles);
+      _itoa_word ((unsigned long int) l->l_ld, &buf1[nibbles], 16, 0);
+      _itoa_word ((unsigned long int) l->l_addr, &buf2[nibbles], 16, 0);
+      _itoa_word (maplength, &buf3[nibbles], 16, 0);
+
+      _dl_debug_message (1, "  dynamic: 0x", buf1, "  base: 0x", buf2,
+			 "   size: 0x", buf3, "\n", NULL);
+      memset (buf1, '0', nibbles);
+      memset (buf2, '0', nibbles);
+      memset (buf3, ' ', nibbles);
+      _itoa_word ((unsigned long int) l->l_entry, &buf1[nibbles], 16, 0);
+      _itoa_word ((unsigned long int) l->l_phdr, &buf2[nibbles], 16, 0);
+      _itoa_word (l->l_phnum, &buf3[nibbles], 10, 0);
+      _dl_debug_message (1, "    entry: 0x", buf1, "  phdr: 0x", buf2,
+			 "  phnum:   ", buf3, "\n\n", NULL);
+    }
+
   elf_get_dynamic_info (l->l_ld, l->l_info);
   if (l->l_info[DT_HASH])
     _dl_setup_hash (l);
@@ -800,7 +838,7 @@ print_search_path (struct r_search_path_elem **list,
 {
   int first = 1;
 
-  _dl_debug_message ("\t search path=", NULL);
+  _dl_debug_message (1, " search path=", NULL);
 
   while (*list != NULL && (*list)->what == what) /* Yes, ==.  */
     {
@@ -809,23 +847,23 @@ print_search_path (struct r_search_path_elem **list,
       if ((*list)->machdirstatus != nonexisting)
 	{
 	  buf[(*list)->machdirnamelen - 1] = '\0';
-	  _dl_debug_message (first ? "" : ":", buf, NULL);
+	  _dl_debug_message (0, first ? "" : ":", buf, NULL);
 	  first = 0;
 	}
       if ((*list)->dirstatus != nonexisting)
 	{
 	  buf[(*list)->dirnamelen - 1] = '\0';
-	  _dl_debug_message (first ? "" : ":", buf, NULL);
+	  _dl_debug_message (0, first ? "" : ":", buf, NULL);
 	  first = 0;
 	}
       ++list;
     }
 
   if (name != NULL)
-    _dl_debug_message ("\t\t(", what, " from file ",
+    _dl_debug_message (0, "\t\t(", what, " from file ",
 			name[0] ? name : _dl_argv[0], ")\n", NULL);
   else
-    _dl_debug_message ("\t\t(", what, ")\n", NULL);
+    _dl_debug_message (0, "\t\t(", what, ")\n", NULL);
 }
 
 /* Try to open NAME in one of the directories in DIRS.
@@ -871,7 +909,7 @@ open_path (const char *name, size_t namelen, int preloaded,
 
           /* Print name we try if this is wanted.  */
 	  if (_dl_debug_libs)
-	    _dl_debug_message ("\t  trying file=", buf, "\n", NULL);
+	    _dl_debug_message (1, "  trying file=", buf, "\n", NULL);
 
 	  fd = __open (buf, O_RDONLY);
 	  if (this_dir->machdirstatus == unknown)
@@ -926,7 +964,7 @@ open_path (const char *name, size_t namelen, int preloaded,
 
 	  /* Print name we try if this is wanted.  */
 	  if (_dl_debug_libs)
-	    _dl_debug_message ("\t  trying file=", buf, "\n", NULL);
+	    _dl_debug_message (1, "  trying file=", buf, "\n", NULL);
 
 	  fd = __open (buf, O_RDONLY);
 	  if (this_dir->dirstatus == unknown)
@@ -1038,6 +1076,12 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       return l;
     }
 
+  /* Display information if we are debugging.  */
+  if (_dl_debug_files && loader != NULL)
+    _dl_debug_message (1, "\nfile=", name, ";  needed by ",
+		       loader->l_name[0] ? loader->l_name : _dl_argv[0],
+		       "\n", NULL);
+
   if (strchr (name, '/') == NULL)
     {
       /* Search for NAME in several places.  */
@@ -1045,7 +1089,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       size_t namelen = strlen (name) + 1;
 
       if (_dl_debug_libs)
-	_dl_debug_message ("\tfind library=", name, "; searching\n", NULL);
+	_dl_debug_message (1, "find library=", name, "; searching\n", NULL);
 
       fd = -1;
 
@@ -1109,7 +1153,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
       /* Add another newline when we a tracing the library loading.  */
       if (_dl_debug_libs)
-        _dl_debug_message ("\n", NULL);
+        _dl_debug_message (1, "\n", NULL);
     }
   else
     {
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 95399ba0b8..f2cd981883 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -100,7 +100,7 @@ do_lookup (const char *undef_name, unsigned long int hash,
 
       /* Print some debugging info if wanted.  */
       if (_dl_debug_symbols)
-	_dl_debug_message ("\tsymbol=", undef_name, ";  lookup in file=",
+	_dl_debug_message (1, "symbol=", undef_name, ";  lookup in file=",
 			   map->l_name[0] ? map->l_name : _dl_argv[0],
 			   "\n", NULL);
 
@@ -236,7 +236,7 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
     }
 
   if (_dl_debug_bindings)
-    _dl_debug_message ("\tbinding file ", reference_name, " to ",
+    _dl_debug_message (1, "binding file ", reference_name, " to ",
 		       current_value.m->l_name[0]
 		       ? current_value.m->l_name : _dl_argv[0],
 		       ": symbol `", undef_name, "'\n", NULL);
@@ -281,7 +281,7 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
     }
 
   if (_dl_debug_bindings)
-    _dl_debug_message ("\tbinding file ", reference_name, " to ",
+    _dl_debug_message (1, "binding file ", reference_name, " to ",
 		       current_value.m->l_name[0]
 		       ? current_value.m->l_name : _dl_argv[0],
 		       ": symbol `", undef_name, "'\n", NULL);
@@ -342,7 +342,7 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
     }
 
   if (_dl_debug_bindings)
-    _dl_debug_message ("\tbinding file ", reference_name, " to ",
+    _dl_debug_message (1, "binding file ", reference_name, " to ",
 		       current_value.m->l_name[0]
 		       ? current_value.m->l_name : _dl_argv[0],
 		       ": symbol `", undef_name, "' [", version->name,
@@ -396,7 +396,7 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
     }
 
   if (_dl_debug_bindings)
-    _dl_debug_message ("\tbinding file ", reference_name, " to ",
+    _dl_debug_message (1, "binding file ", reference_name, " to ",
 		       current_value.m->l_name[0]
 		       ? current_value.m->l_name : _dl_argv[0],
 		       ": symbol `", undef_name, "' [", version->name,
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index 90288525f4..1e13d0d28a 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -22,8 +22,10 @@
 #include <unistd.h>
 #include <stdarg.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <stdio-common/_itoa.h>
 
 #ifndef MAP_ANON
 /* This is the only dl-sysdep.c function that is actually needed at run-time
@@ -89,6 +91,54 @@ _dl_sysdep_output (int fd, const char *msg, ...)
       size_t len = strlen (msg);
       __write (fd, msg, len);
       msg = va_arg (ap, const char *);
-    } while (msg);
+    }
+  while (msg != NULL);
+  va_end (ap);
+}
+
+
+void
+_dl_debug_message (int new_line, const char *msg, ...)
+{
+  /* We print the strings we get passed one after the other but start all
+     lines using the current PID.  */
+  static int pid;
+  va_list ap;
+
+  if (pid == 0)
+    pid = getpid ();
+
+  va_start (ap, msg);
+  do
+    if (msg[0] == '\0')
+      /* Get the next argument.  */
+      msg = va_arg (ap, const char *);
+    else
+      {
+	const char *endp;
+
+	/* We actually will print something in this line.  So print the
+	   PID now if needed.  */
+	if (new_line)
+	  {
+	    char buf[7] = "00000:\t";
+	    __write (_dl_debug_fd, _itoa_word (pid, &buf[5], 10, 0), 7);
+	    new_line = 0;
+	  }
+
+	endp = strchr (msg, '\n');
+	if (endp == NULL)
+	  {
+	    __write (_dl_debug_fd, msg, strlen (msg));
+	    msg = va_arg (ap, const char *);
+	  }
+	else
+	  {
+	    __write (_dl_debug_fd, msg, endp - msg + 1);
+	    msg = endp + 1;
+	    new_line = 1;
+	  }
+      }
+  while (msg != NULL);
   va_end (ap);
 }
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 531da9618a..d38c6c13a0 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -32,6 +32,10 @@ _dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy)
   if (l->l_relocated)
     return;
 
+  if (_dl_debug_reloc)
+    _dl_debug_message (1, "\nrelocation processing: ",
+		       l->l_name[0] ? l->l_name : _dl_argv[0], "\n", NULL);
+
   if (l->l_info[DT_TEXTREL])
     {
       /* Bletch.  We must make read-only segments writable
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 39fa47cd4d..0f3a4c5f66 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -39,6 +39,9 @@ int _dl_debug_libs;
 int _dl_debug_impcalls;
 int _dl_debug_bindings;
 int _dl_debug_symbols;
+int _dl_debug_versions;
+int _dl_debug_reloc;
+int _dl_debug_files;
 
 /* If nonzero print warnings about problematic situations.  */
 int _dl_verbose;
diff --git a/elf/dl-version.c b/elf/dl-version.c
index f615bb0cbc..a8bdeef89b 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -79,6 +79,12 @@ match_symbol (const char *name, ElfW(Word) hash, const char *string,
   ElfW(Addr) def_offset;
   ElfW(Verdef) *def;
 
+  /* Display information about what we are doing while debugging.  */
+  if (_dl_debug_versions)
+    _dl_debug_message (1, "checking for version `", string, "' in file ",
+		       map->l_name[0] ? map->l_name : _dl_argv[0],
+		       " required by file ", name, "\n", NULL);
+
   if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
     {
       /* The file has no symbol versioning.  I.e., the dependent
diff --git a/elf/link.h b/elf/link.h
index b2eb572d77..bd9b9e476d 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -253,6 +253,9 @@ extern int _dl_debug_libs;
 extern int _dl_debug_impcalls;
 extern int _dl_debug_bindings;
 extern int _dl_debug_symbols;
+extern int _dl_debug_versions;
+extern int _dl_debug_reloc;
+extern int _dl_debug_files;
 
 /* File deccriptor to write debug messages to.  */
 extern int _dl_debug_fd;
@@ -267,9 +270,10 @@ extern void _dl_sysdep_output (int fd, const char *string, ...);
 
 /* OS-dependent function to write a debug message on the specified
    descriptor for this.  All arguments are `const char *'; args until
-   a null pointer are concatenated to form the message to print.  */
-#define _dl_debug_message(string, args...) \
-  _dl_sysdep_output (_dl_debug_fd, string, ##args)
+   a null pointer are concatenated to form the message to print.  If
+   NEW_LINE is nonzero it is assumed that the message starts on a new
+   line.*/
+extern void _dl_debug_message (int new_line, const char *string, ...);
 
 /* OS-dependent function to write a message on the standard output.
    All arguments are `const char *'; args until a null pointer
diff --git a/elf/rtld.c b/elf/rtld.c
index 2db6cf3613..8b72d07883 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -78,6 +78,9 @@ int _dl_debug_libs;
 int _dl_debug_impcalls;
 int _dl_debug_bindings;
 int _dl_debug_symbols;
+int _dl_debug_versions;
+int _dl_debug_reloc;
+int _dl_debug_files;
 
 /* Set nonzero during loading and initialization of executable and
    libraries, cleared before the executable's entry point runs.  This
@@ -927,21 +930,21 @@ process_dl_debug (char *dl_debug)
 	++dl_debug;
       if (*dl_debug != '\0')
 	{
-	  if (strncmp (dl_debug, "bindings", 8) == 0
-	      && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
+	  if (strncmp (dl_debug, "files", 5) == 0
+	      && (issep (dl_debug[5]) || dl_debug[5] == '\0'))
 	    {
-	      _dl_debug_bindings = 1;
+	      _dl_debug_files = 1;
 	      _dl_debug_impcalls = 1;
 	      any_debug = 1;
-	      dl_debug += 8;
+	      dl_debug += 5;
 	    }
-	  else if (strncmp (dl_debug, "libs", 4) == 0
-	      && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+	  else if (strncmp (dl_debug, "bindings", 8) == 0
+	      && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
 	    {
-	      _dl_debug_libs = 1;
+	      _dl_debug_bindings = 1;
 	      _dl_debug_impcalls = 1;
 	      any_debug = 1;
-	      dl_debug += 4;
+	      dl_debug += 8;
 	    }
 	  else if (strncmp (dl_debug, "help", 4) == 0
 		   && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
@@ -950,15 +953,34 @@ process_dl_debug (char *dl_debug)
 Valid options for the LD_DEBUG environment variable are:\n\
 \n\
   bindings  display information about symbol binding\n\
+  files     display processing of files and libraries\n\
   help      display this help message and exit\n\
   libs      display library search paths\n\
+  reloc     display relocation processing\n\
   symbols   display symbol table processing\n\
+  versions  display version dependencies\n\
 \n\
 To direct the debugging output into a file instead of standard output\n\
 a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n",
 				  NULL);
 	      _exit (0);
 	    }
+	  else if (strncmp (dl_debug, "libs", 4) == 0
+	      && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+	    {
+	      _dl_debug_libs = 1;
+	      _dl_debug_impcalls = 1;
+	      any_debug = 1;
+	      dl_debug += 4;
+	    }
+	  else if (strncmp (dl_debug, "reloc", 4) == 0
+	      && (issep (dl_debug[5]) || dl_debug[5] == '\0'))
+	    {
+	      _dl_debug_reloc = 1;
+	      _dl_debug_impcalls = 1;
+	      any_debug = 1;
+	      dl_debug += 5;
+	    }
 	  else if (strncmp (dl_debug, "symbols", 7) == 0
 	      && (issep (dl_debug[7]) || dl_debug[7] == '\0'))
 	    {
@@ -967,6 +989,14 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n",
 	      any_debug = 1;
 	      dl_debug += 7;
 	    }
+	  else if (strncmp (dl_debug, "versions", 8) == 0
+	      && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
+	    {
+	      _dl_debug_versions = 1;
+	      _dl_debug_impcalls = 1;
+	      any_debug = 1;
+	      dl_debug += 8;
+	    }
 	  else
 	    {
 	      /* Display a warning and skip everything until next
diff --git a/libc.map b/libc.map
index 4388fb50b3..dc7037b358 100644
--- a/libc.map
+++ b/libc.map
@@ -99,6 +99,7 @@ GLIBC_2.0 {
     _rpc_dtablesize; _null_auth; _seterr_reply;
     __res_randomid;  __getpid;
     __strcasecmp; __write; _strerror_internal; _dl_sysdep_output;
+    _dl_debug_message;
     __ffs;
 
     # Exception handling support functions from libgcc
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 75cfe5f360..2a94caa367 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -89,8 +89,19 @@ struct test_case_struct
 
 static int testit (struct test_case_struct *tc);
 
+void
+command_line_test (const char *words)
+{
+  wordexp_t we;
+  int i;
+  int retval = wordexp (words, &we, 0);
+  printf ("wordexp returned %d\n", retval);
+  for (i = 0; i < we.we_wordc; i++)
+    printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
+}
+
 int
-main (int argc, char * argv[])
+main (int argc, char *argv[])
 {
   struct passwd *pw;
   int test;
@@ -101,6 +112,12 @@ main (int argc, char * argv[])
     if (testit (&test_case[test]))
       ++fail;
 
+  if (argc > 1)
+    {
+      command_line_test (argv[1]);
+      return 0;
+    }
+
   pw = getpwnam ("root");
   if (pw != NULL)
     {
diff --git a/sysdeps/unix/sysv/linux/libc-start.c b/sysdeps/unix/sysv/linux/libc-start.c
index 5e089d4ebb..d32e54f162 100644
--- a/sysdeps/unix/sysv/linux/libc-start.c
+++ b/sysdeps/unix/sysv/linux/libc-start.c
@@ -50,14 +50,14 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
   /* Call the initializer of the libc.  */
 #ifdef PIC
   if (_dl_debug_impcalls)
-    _dl_debug_message ("\tinitialize libc\n\n", NULL);
+    _dl_debug_message (1, "\ninitialize libc\n\n", NULL);
 #endif
   __libc_init_first (argc, argv, __environ);
 
   /* Call the initializer of the program.  */
 #ifdef PIC
   if (_dl_debug_impcalls)
-    _dl_debug_message ("\tinitialize program: ", argv[0], "\n\n", NULL);
+    _dl_debug_message (1, "\ninitialize program: ", argv[0], "\n\n", NULL);
 #endif
   (*init) ();
 
@@ -66,7 +66,7 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
 
 #ifdef PIC
   if (_dl_debug_impcalls)
-    _dl_debug_message ("\ttransferring control: ", argv[0], "\n\n", NULL);
+    _dl_debug_message (1, "\ntransferring control: ", argv[0], "\n\n", NULL);
 #endif
 
   exit ((*main) (argc, argv, __environ));
diff --git a/sysdeps/unix/sysv/linux/sys/quota.h b/sysdeps/unix/sysv/linux/sys/quota.h
index 47e88d7176..bcbbfa5ddb 100644
--- a/sysdeps/unix/sysv/linux/sys/quota.h
+++ b/sysdeps/unix/sysv/linux/sys/quota.h
@@ -1,3 +1,161 @@
-/* The kernel header file contains all declarations and definitions.  */
+/* This just represents the non-kernel parts of <linux/quota.h>.
+ *
+ * here's the corresponding copyright:
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *   This product includes software developed by the University of
+ *   California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Version: $Id$
+ */
+
+#ifndef _SYS_QUOTA_H
+#define _SYS_QUOTA_H 1
+
+#include <features.h>
 #include <sys/types.h>
-#include <linux/quota.h>
+
+/*
+ * Convert diskblocks to blocks and the other way around.
+ * currently only to fool the BSD source. :-)
+ */
+#define dbtob(num) ((num) << 10)
+#define btodb(num) ((num) >> 10)
+
+/*
+ * Convert count of filesystem blocks to diskquota blocks, meant
+ * for filesystems where i_blksize != BLOCK_SIZE
+ */
+#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+
+#define MAXQUOTAS 2
+#define USRQUOTA  0		/* element used for user quotas */
+#define GRPQUOTA  1		/* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+   "user",      /* USRQUOTA */ \
+   "group",   /* GRPQUOTA */ \
+   "undefined", \
+};
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "staff"
+
+#define NR_DQHASH 43          /* Just an arbitrary number any suggestions ? */
+#define NR_DQUOTS 256         /* Number of quotas active at one time */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK  0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_QUOTAON  0x0100	/* enable quotas */
+#define Q_QUOTAOFF 0x0200	/* disable quotas */
+#define Q_GETQUOTA 0x0300	/* get limits and usage */
+#define Q_SETQUOTA 0x0400	/* set limits and usage */
+#define Q_SETUSE   0x0500	/* set usage */
+#define Q_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
+#define Q_SETQLIM  0x0700	/* set limits */
+#define Q_GETSTATS 0x0800	/* get collected stats */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct dqblk
+  {
+    u_int32_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+    u_int32_t dqb_bsoftlimit;	/* preferred limit on disk blks */
+    u_int32_t dqb_curblocks;	/* current block count */
+    u_int32_t dqb_ihardlimit;	/* maximum # allocated inodes */
+    u_int32_t dqb_isoftlimit;	/* preferred inode limit */
+    u_int32_t dqb_curinodes;	/* current # allocated inodes */
+    time_t dqb_btime;		/* time limit for excessive disk use */
+    time_t dqb_itime;		/* time limit for excessive files */
+  };
+
+/*
+ * Shorthand notation.
+ */
+#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
+#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
+#define	dq_curblocks	dq_dqb.dqb_curblocks
+#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
+#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
+#define	dq_curinodes	dq_dqb.dqb_curinodes
+#define	dq_btime	dq_dqb.dqb_btime
+#define	dq_itime	dq_dqb.dqb_itime
+
+#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
+
+struct dqstats
+  {
+    u_int32_t lookups;
+    u_int32_t drops;
+    u_int32_t reads;
+    u_int32_t writes;
+    u_int32_t cache_hits;
+    u_int32_t pages_allocated;
+    u_int32_t allocated_dquots;
+    u_int32_t free_dquots;
+    u_int32_t syncs;
+  };
+
+__BEGIN_DECLS
+
+extern int quotactl __P ((int __cmd, const char *__special, int __id,
+			  caddr_t __addr));
+
+__END_DECLS
+
+#endif /* sys/quota.h */