78dd4e4
diff -Nrup a/elf/dl-close.c b/elf/dl-close.c
78dd4e4
--- a/elf/dl-close.c	2012-06-30 13:12:34.000000000 -0600
78dd4e4
+++ b/elf/dl-close.c	2012-08-20 11:07:56.027477028 -0600
f7dfce4
@@ -31,6 +31,7 @@
c89b9e0
 #include <sys/mman.h>
c89b9e0
 #include <sysdep-cancel.h>
c89b9e0
 #include <tls.h>
c89b9e0
+#include <stap-probe.h>
c89b9e0
 
c89b9e0
 
c89b9e0
 /* Type of the constructor functions.  */
f7dfce4
@@ -468,6 +469,7 @@ _dl_close_worker (struct link_map *map)
c89b9e0
   struct r_debug *r = _dl_debug_initialize (0, nsid);
c89b9e0
   r->r_state = RT_DELETE;
c89b9e0
   _dl_debug_state ();
78dd4e4
+  LIBC_PROBE (unmap_start, 2, nsid, r);
c89b9e0
 
c89b9e0
   if (unload_global)
c89b9e0
     {
78dd4e4
@@ -484,7 +486,7 @@ _dl_close_worker (struct link_map *map)
78dd4e4
 	/* Speed up removing most recently added objects.  */
78dd4e4
 	j = cnt;
78dd4e4
       else
78dd4e4
- 	for (i = 0; i < cnt; i++)
78dd4e4
+	for (i = 0; i < cnt; i++)
78dd4e4
 	  if (ns_msl->r_list[i]->l_removed == 0)
78dd4e4
 	    {
78dd4e4
 	      if (i != j)
78dd4e4
@@ -640,6 +642,10 @@ _dl_close_worker (struct link_map *map)
78dd4e4
 	      assert (nsid != LM_ID_BASE);
78dd4e4
 #endif
78dd4e4
 	      ns->_ns_loaded = imap->l_next;
78dd4e4
+
78dd4e4
+	      /* Update the pointer to the head of the list
78dd4e4
+		 we leave for debuggers to examine.  */
78dd4e4
+	      r->r_map = (void *) ns->_ns_loaded;
78dd4e4
 	    }
78dd4e4
 
78dd4e4
 	  --ns->_ns_nloaded;
78dd4e4
@@ -737,6 +743,7 @@ _dl_close_worker (struct link_map *map)
c89b9e0
   /* Notify the debugger those objects are finalized and gone.  */
c89b9e0
   r->r_state = RT_CONSISTENT;
c89b9e0
   _dl_debug_state ();
78dd4e4
+  LIBC_PROBE (unmap_complete, 2, nsid, r);
c89b9e0
 
c89b9e0
   /* Recheck if we need to retry, release the lock.  */
c89b9e0
  out:
78dd4e4
diff -Nrup a/elf/dl-load.c b/elf/dl-load.c
78dd4e4
--- a/elf/dl-load.c	2012-08-20 11:05:53.042962577 -0600
78dd4e4
+++ b/elf/dl-load.c	2012-08-20 11:06:30.009816633 -0600
f7dfce4
@@ -35,6 +35,7 @@
c89b9e0
 #include <stackinfo.h>
c89b9e0
 #include <caller.h>
c89b9e0
 #include <sysdep.h>
c89b9e0
+#include <stap-probe.h>
c89b9e0
 
c89b9e0
 #include <dl-dst.h>
c89b9e0
 
f7dfce4
@@ -880,7 +881,7 @@ _dl_init_paths (const char *llp)
c89b9e0
 static void
c89b9e0
 __attribute__ ((noreturn, noinline))
c89b9e0
 lose (int code, int fd, const char *name, char *realname, struct link_map *l,
c89b9e0
-      const char *msg, struct r_debug *r)
c89b9e0
+      const char *msg, struct r_debug *r, Lmid_t nsid)
c89b9e0
 {
c89b9e0
   /* The file might already be closed.  */
c89b9e0
   if (fd != -1)
f7dfce4
@@ -894,6 +895,7 @@ lose (int code, int fd, const char *name
c89b9e0
     {
c89b9e0
       r->r_state = RT_CONSISTENT;
c89b9e0
       _dl_debug_state ();
78dd4e4
+      LIBC_PROBE (map_failed, 2, nsid, r);
c89b9e0
     }
c89b9e0
 
c89b9e0
   _dl_signal_error (code, name, NULL, msg);
f7dfce4
@@ -932,7 +934,7 @@ _dl_map_object_from_fd (const char *name
c89b9e0
       errval = errno;
c89b9e0
     call_lose:
c89b9e0
       lose (errval, fd, name, realname, l, errstring,
c89b9e0
-	    make_consistent ? r : NULL);
c89b9e0
+	    make_consistent ? r : NULL, nsid);
c89b9e0
     }
c89b9e0
 
c89b9e0
   /* Look again to see if the real name matched another already loaded.  */
f7dfce4
@@ -1039,6 +1041,7 @@ _dl_map_object_from_fd (const char *name
c89b9e0
 	 linking has not been used before.  */
c89b9e0
       r->r_state = RT_ADD;
c89b9e0
       _dl_debug_state ();
78dd4e4
+      LIBC_PROBE (map_start, 2, nsid, r);
c89b9e0
       make_consistent = true;
c89b9e0
     }
c89b9e0
   else
78dd4e4
@@ -1744,7 +1747,7 @@ open_verify (const char *name, struct fi
c89b9e0
 	      name = strdupa (realname);
c89b9e0
 	      free (realname);
c89b9e0
 	    }
c89b9e0
-	  lose (errval, fd, name, NULL, NULL, errstring, NULL);
c89b9e0
+	  lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
c89b9e0
 	}
c89b9e0
 
c89b9e0
       /* See whether the ELF header is what we expect.  */
78dd4e4
diff -Nrup a/elf/dl-open.c b/elf/dl-open.c
78dd4e4
--- a/elf/dl-open.c	2012-06-30 13:12:34.000000000 -0600
78dd4e4
+++ b/elf/dl-open.c	2012-08-20 11:06:30.010816629 -0600
f7dfce4
@@ -32,6 +32,7 @@
c89b9e0
 #include <caller.h>
c89b9e0
 #include <sysdep-cancel.h>
c89b9e0
 #include <tls.h>
c89b9e0
+#include <stap-probe.h>
c89b9e0
 
c89b9e0
 #include <dl-dst.h>
c89b9e0
 
f7dfce4
@@ -291,6 +292,7 @@ dl_open_worker (void *a)
c89b9e0
   struct r_debug *r = _dl_debug_initialize (0, args->nsid);
c89b9e0
   r->r_state = RT_CONSISTENT;
c89b9e0
   _dl_debug_state ();
78dd4e4
+  LIBC_PROBE (map_complete, 3, args->nsid, r, new);
c89b9e0
 
c89b9e0
   /* Print scope information.  */
c89b9e0
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES, 0))
f7dfce4
@@ -376,10 +378,19 @@ dl_open_worker (void *a)
f7dfce4
 	}
f7dfce4
     }
f7dfce4
 
c89b9e0
+  int relocation_in_progress = 0;
f7dfce4
+
f7dfce4
   for (size_t i = nmaps; i-- > 0; )
c89b9e0
     {
f7dfce4
       l = maps[i];
f7dfce4
 
f7dfce4
+      if (! relocation_in_progress)
f7dfce4
+	{
f7dfce4
+	  /* Notify the debugger that relocations are about to happen.  */
78dd4e4
+	  LIBC_PROBE (reloc_start, 2, args->nsid, r);
f7dfce4
+	  relocation_in_progress = 1;
f7dfce4
+	}
c89b9e0
+
c89b9e0
 #ifdef SHARED
f7dfce4
       if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
f7dfce4
 	{
f7dfce4
@@ -544,6 +555,10 @@ cannot load any more object with static
c89b9e0
 	}
c89b9e0
     }
c89b9e0
 
c89b9e0
+  /* Notify the debugger all new objects have been relocated.  */
c89b9e0
+  if (relocation_in_progress)
78dd4e4
+    LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
c89b9e0
+
c89b9e0
   /* Run the initializer functions of new objects.  */
c89b9e0
   _dl_init (new, args->argc, args->argv, args->env);
c89b9e0
 
78dd4e4
diff -Nrup a/elf/rtld-debugger-interface.txt b/elf/rtld-debugger-interface.txt
78dd4e4
--- a/elf/rtld-debugger-interface.txt	1969-12-31 17:00:00.000000000 -0700
78dd4e4
+++ b/elf/rtld-debugger-interface.txt	2012-08-20 11:06:30.011816625 -0600
78dd4e4
@@ -0,0 +1,122 @@
78dd4e4
+Standard debugger interface
78dd4e4
+===========================
78dd4e4
+
78dd4e4
+The run-time linker exposes a rendezvous structure to allow debuggers
78dd4e4
+to interface with it.  This structure, r_debug, is defined in link.h.
78dd4e4
+If the executable's dynamic section has a DT_DEBUG element, the
78dd4e4
+run-time linker sets that element's value to the address where this
78dd4e4
+structure can be found.
78dd4e4
+
78dd4e4
+The r_debug structure contains (amongst others) the following fields:
78dd4e4
+
78dd4e4
+  struct link_map *r_map:
78dd4e4
+    A linked list of loaded objects.
78dd4e4
+
78dd4e4
+  enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state:
78dd4e4
+    The current state of the r_map list.  RT_CONSISTENT means that r_map
78dd4e4
+    is not currently being modified and may safely be inspected.  RT_ADD
78dd4e4
+    means that an object is being added to r_map, and that the list is
78dd4e4
+    not guaranteed to be consistent.  Likewise RT_DELETE means that an
78dd4e4
+    object is being removed from the list.
78dd4e4
+
78dd4e4
+  ElfW(Addr) r_brk:
78dd4e4
+    The address of a function internal to the run-time linker which is
78dd4e4
+    called whenever r_state is changed.  The debugger should set a
78dd4e4
+    breakpoint at this address if it wants to notice mapping changes.
78dd4e4
+
78dd4e4
+This protocol is widely supported, but somewhat limited in that it
78dd4e4
+has no provision to provide access to multiple namespaces, and that
78dd4e4
+the notifications (via r_brk) only refer to changes to r_map--the
78dd4e4
+debugger is notified that a new object has been added, for instance,
78dd4e4
+but there is no way for the debugger to discover whether any of the
78dd4e4
+objects in the link-map have been relocated or not.
78dd4e4
+
78dd4e4
+
78dd4e4
+Probe-based debugger interface
78dd4e4
+==============================
78dd4e4
+
78dd4e4
+Systemtap is a dynamic tracing/instrumenting tool available on Linux.
78dd4e4
+Probes that are not fired at run time have close to zero overhead.
78dd4e4
+glibc contains a number of probes that debuggers can set breakpoints
78dd4e4
+on in order to notice certain events.
78dd4e4
+
78dd4e4
+All rtld probes have the following arguments:
78dd4e4
+
78dd4e4
+  arg1: Lmid_t lmid:
78dd4e4
+    The link-map ID of the link-map list that the object was loaded
78dd4e4
+    into.  This will be LM_ID_BASE for the application's main link-map
78dd4e4
+    list, or some other value for different namespaces.
78dd4e4
+
78dd4e4
+  arg2: struct r_debug *r_debug:
78dd4e4
+    A pointer to the r_debug structure containing the link-map list
78dd4e4
+    that the object was loaded into.  This will be the value stored in
78dd4e4
+    DT_DEBUG for the application's main link-map list, or some other
78dd4e4
+    value for different namespaces.
78dd4e4
+
78dd4e4
+map_complete and reloc_complete may have the following additional
78dd4e4
+argument:
78dd4e4
+
78dd4e4
+  arg3: struct link_map *new:
78dd4e4
+    A pointer which, if not NULL, points to the entry in the specified
78dd4e4
+    r_debug structure's link-map list corresponding to the first new
78dd4e4
+    object to have been mapped or relocated, with new->l_next pointing
78dd4e4
+    to the link-map of the next new object to have been mapped or
78dd4e4
+    relocated, and so on.  Note that because `new' is an entry in a
78dd4e4
+    larger list, new->l_prev (if not NULL) will point to what was the
78dd4e4
+    last link-map in the link-map list prior to the new objects being
78dd4e4
+    mapped or relocated.
78dd4e4
+
78dd4e4
+The following probes are available:
78dd4e4
+
78dd4e4
+  init_start:
78dd4e4
+    This is called once, when the linker is about to fill in the main
78dd4e4
+    r_debug structure at application startup.  init_start always has
78dd4e4
+    lmid set to LM_ID_BASE and r_debug set to the value stored in
78dd4e4
+    DT_DEBUG.  r_debug is not guaranteed to be consistent until
78dd4e4
+    init_complete is fired.
78dd4e4
+
78dd4e4
+  init_complete:
78dd4e4
+    This is called once, when the linker has filled in the main
78dd4e4
+    r_debug structure at application startup. init_complete always
78dd4e4
+    has lmid set to LM_ID_BASE and r_debug set to the value stored
78dd4e4
+    in DT_DEBUG.  The r_debug structure is consistent and may be
78dd4e4
+    inspected, and all objects in the link-map are guaranteed to
78dd4e4
+    have been relocated.
78dd4e4
+
78dd4e4
+  map_start:
78dd4e4
+    The linker is about to map new objects into the specified
78dd4e4
+    namespace.  The namespace's r_debug structure is not guaranteed
78dd4e4
+    to be consistent until a corresponding map_complete is fired.
78dd4e4
+
78dd4e4
+  map_complete:
78dd4e4
+    The linker has finished mapping new objects into the specified
78dd4e4
+    namespace.  The namespace's r_debug structure is consistent and
78dd4e4
+    may be inspected, although objects in the namespace's link-map
78dd4e4
+    are not guaranteed to have been relocated.
78dd4e4
+
78dd4e4
+  map_failed:
78dd4e4
+    The linker failed while attempting to map new objects into
78dd4e4
+    the specified namespace.  The namespace's r_debug structure
78dd4e4
+    is consistent and may be inspected.
78dd4e4
+
78dd4e4
+  reloc_start:
78dd4e4
+    The linker is about to relocate all unrelocated objects in the
78dd4e4
+    specified namespace.  The namespace's r_debug structure is not
78dd4e4
+    guaranteed to be consistent until a corresponding reloc_complete
78dd4e4
+    is fired.
78dd4e4
+
78dd4e4
+  reloc_complete:
78dd4e4
+    The linker has relocated all objects in the specified namespace.
78dd4e4
+    The namespace's r_debug structure is consistent and may be
78dd4e4
+    inspected, and all objects in the namespace's link-map are
78dd4e4
+    guaranteed to have been relocated.
78dd4e4
+
78dd4e4
+  unmap_start:
78dd4e4
+    The linker is about to remove objects from the specified
78dd4e4
+    namespace.  The namespace's r_debug structure is not guaranteed to
78dd4e4
+    be consistent until a corresponding unmap_complete is fired.
78dd4e4
+
78dd4e4
+  unmap_complete:
78dd4e4
+    The linker has finished removing objects into the specified
78dd4e4
+    namespace.  The namespace's r_debug structure is consistent and
78dd4e4
+    may be inspected.
78dd4e4
diff -Nrup a/elf/rtld.c b/elf/rtld.c
78dd4e4
--- a/elf/rtld.c	2012-08-20 11:05:52.905963117 -0600
78dd4e4
+++ b/elf/rtld.c	2012-08-20 11:06:30.016816605 -0600
f7dfce4
@@ -39,6 +39,7 @@
c89b9e0
 #include <dl-osinfo.h>
c89b9e0
 #include <dl-procinfo.h>
c89b9e0
 #include <tls.h>
c89b9e0
+#include <stap-probe.h>
c89b9e0
 #include <stackinfo.h>
c89b9e0
 
c89b9e0
 #include <assert.h>
f7dfce4
@@ -1681,6 +1682,7 @@ ERROR: ld.so: object '%s' cannot be load
c89b9e0
   /* We start adding objects.  */
c89b9e0
   r->r_state = RT_ADD;
c89b9e0
   _dl_debug_state ();
78dd4e4
+  LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
c89b9e0
 
c89b9e0
   /* Auditing checkpoint: we are ready to signal that the initial map
c89b9e0
      is being constructed.  */
78dd4e4
@@ -2399,6 +2401,7 @@ ERROR: ld.so: object '%s' cannot be load
c89b9e0
   r = _dl_debug_initialize (0, LM_ID_BASE);
c89b9e0
   r->r_state = RT_CONSISTENT;
c89b9e0
   _dl_debug_state ();
78dd4e4
+  LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
c89b9e0
 
c89b9e0
 #ifndef MAP_COPY
c89b9e0
   /* We must munmap() the cache file.  */