From nobody@FreeBSD.org  Mon Feb  3 23:38:29 2014
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTPS id 0F014AC4
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  3 Feb 2014 23:38:29 +0000 (UTC)
Received: from oldred.freebsd.org (oldred.freebsd.org [IPv6:2001:1900:2254:206a::50:4])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by mx1.freebsd.org (Postfix) with ESMTPS id EEEF01452
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  3 Feb 2014 23:38:28 +0000 (UTC)
Received: from oldred.freebsd.org ([127.0.1.6])
	by oldred.freebsd.org (8.14.5/8.14.7) with ESMTP id s13NcS0r021155
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 3 Feb 2014 23:38:28 GMT
	(envelope-from nobody@oldred.freebsd.org)
Received: (from nobody@localhost)
	by oldred.freebsd.org (8.14.5/8.14.5/Submit) id s13NcShD021154;
	Mon, 3 Feb 2014 23:38:28 GMT
	(envelope-from nobody)
Message-Id: <201402032338.s13NcShD021154@oldred.freebsd.org>
Date: Mon, 3 Feb 2014 23:38:28 GMT
From: Yuri <yuri@rawbw.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [patch] Allow for an alternative run-time loader
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         186435
>Category:       kern
>Synopsis:       [libexec] [patch] Allow for an alternative run-time loader
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 03 23:40:01 UTC 2014
>Closed-Date:    
>Last-Modified:  Mon Feb 24 07:07:23 UTC 2014
>Originator:     Yuri
>Release:        9.2
>Organization:
n/a
>Environment:
>Description:
Synopsys:
This is a simple patch to run-time loader, which allows other parts of the process to load objects dynamically.

What this patch does:
This patch makes r_debug and related symbols in the ld-elf.so.1 run-time loader public.

Detailed description:
Currently, only r_debug_symbol is public out of all debugger-related symbols in ld-elf.so. This is done so that debuggers can add a breakpoint on it to get notified of changes in the set of loaded shared libraries. This is sufficient when ld-elf.so is the only one who loads objects.

Now imagine the situation when an application wants to load its own ELF objects in its own way, still having the benefit of using the debug info. Such application would need to have access to the list of objects maintained by ld-elf.so. r_debug variable contains this list.

Such application would necessarily be system specific, and would have to have the knowledge of some inner workings of ld-elf.so. But, in my opinion, this is a legitimate use and should be allowed. Therefore I am suggesting this patch. Except r_debug, it adds related lock object and functions to the list of publics, because they are needed to avoid race conditions.

This is, of course, not a mainstream way to do things, but nevertheless it should be allowed.
This is also a minor patch, and it can't possibly hurt anything else.

--begin patch--
--- libexec/rtld-elf/Symbol.map  (revision 260894)
+++ libexec/rtld-elf/Symbol.map  (working copy)
@@ -15,6 +15,11 @@
     dlinfo;
     dl_iterate_phdr;
     r_debug_state;
+    r_debug;
+    rtld_bind_lock;
+    rlock_acquire;
+    wlock_acquire;
+    lock_release;
     __tls_get_addr;
 };

--end patch--

>How-To-Repeat:

>Fix:


>Release-Note:
>Audit-Trail:

From: Alexander Kabaev <kabaev@gmail.com>
To: bug-followup@FreeBSD.org, yuri@rawbw.com
Cc:  
Subject: Re: misc/186435: [patch] Allow for an alternative run-time loader
Date: Sat, 22 Feb 2014 19:06:01 -0500

 --Sig_/Tb3vvaIPFtNSK39JaXljUWg
 Content-Type: text/plain; charset=US-ASCII
 Content-Transfer-Encoding: quoted-printable
 
 I do not like this patch at all, sorry. While I do appreciate the goal,
 the way taken here is just wrong - the locking done by rtld internally
 is just that - internal detail that is not to be paraded publicly in
 front of an an innocent outside world. Over several last years we have
 been over several lock implementations and locking semantics have
 changed subtly couple more times. Would you be willing instead to
 formulate a functional interface that rtld can expose to provide
 necessary services to add/remove dynamic objects and that will allow us
 to keep all of this dirty laundry under the wraps?
 =20
 The patch as is cannot be committed.
 
 --=20
 Alexander Kabaev
 
 --Sig_/Tb3vvaIPFtNSK39JaXljUWg
 Content-Type: application/pgp-signature; name=signature.asc
 Content-Disposition: attachment; filename=signature.asc
 
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (FreeBSD)
 
 iD8DBQFTCTtuQ6z1jMm+XZYRAo4kAKDeEmJUOFOGCBHCW0mIJHGmIoHVGQCdHghZ
 nfpWQhdtTvw4/Tu4Z+t3Nhw=
 =pS/v
 -----END PGP SIGNATURE-----
 
 --Sig_/Tb3vvaIPFtNSK39JaXljUWg--

From: Yuri <yuri@rawbw.com>
To: bug-followup@FreeBSD.org
Cc: Alexander Kabaev <kabaev@gmail.com>
Subject: Re: misc/186435: [patch] Allow for an alternative run-time loader
Date: Sun, 23 Feb 2014 00:50:37 -0800

 This is a multi-part message in MIME format.
 --------------010107090807030709030204
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 Yes, I knew that exposing locks is not nice. However, the upside was 
 that the patch was extremely simple.
 
 I reworked it into the proper implementation. I added r_debug_add and 
 r_debug_delete, with all locks hidden in them. They by themselves are 
 sufficient for the goal. I also added r_debug_iterate, in order to 
 potentially gain access to the list we are manipulating with. This is 
 just in order to not lose any functionality that was made available with 
 the previous patch.
 
 Yuri
 
 --------------010107090807030709030204
 Content-Type: text/plain; charset=UTF-8;
  name="patch-rtld-elf-alt-loader.patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="patch-rtld-elf-alt-loader.patch"
 
 Index: libexec/rtld-elf/Symbol.map
 ===================================================================
 --- libexec/rtld-elf/Symbol.map	(revision 260894)
 +++ libexec/rtld-elf/Symbol.map	(working copy)
 @@ -15,6 +15,9 @@
      dlinfo;
      dl_iterate_phdr;
      r_debug_state;
 +    r_debug_add;
 +    r_debug_delete;
 +    r_debug_iterate;
      __tls_get_addr;
  };
  
 Index: libexec/rtld-elf/rtld.c
 ===================================================================
 --- libexec/rtld-elf/rtld.c	(revision 260894)
 +++ libexec/rtld-elf/rtld.c	(working copy)
 @@ -100,8 +100,10 @@
  static void init_rtld(caddr_t, Elf_Auxinfo **);
  static void initlist_add_neededs(Needed_Entry *, Objlist *);
  static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
 -static void linkmap_add(Obj_Entry *);
 -static void linkmap_delete(Obj_Entry *);
 +static void linkmap_add_obj(Obj_Entry *);
 +static void linkmap_add_map(struct link_map *);
 +static void linkmap_delete_obj(Obj_Entry *);
 +static void linkmap_delete_map(struct link_map *);
  static void load_filtees(Obj_Entry *, int flags, RtldLockState *);
  static void unload_filtees(Obj_Entry *);
  static int load_needed_objects(Obj_Entry *, int);
 @@ -513,8 +515,8 @@
  	obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu,
  	obj_main->dynsymcount);
  
 -    linkmap_add(obj_main);
 -    linkmap_add(&obj_rtld);
 +    linkmap_add_obj(obj_main);
 +    linkmap_add_obj(&obj_rtld);
  
      /* Link the main program into the list of objects. */
      *obj_tail = obj_main;
 @@ -2155,7 +2157,7 @@
      obj_tail = &obj->next;
      obj_count++;
      obj_loads++;
 -    linkmap_add(obj);	/* for GDB & dlinfo() */
 +    linkmap_add_obj(obj);	/* for GDB & dlinfo() */
      max_stack_flags |= obj->stack_flags;
  
      dbg("  %p .. %p: %s", obj->mapbase,
 @@ -3428,19 +3430,26 @@
  }
  
  static void
 -linkmap_add(Obj_Entry *obj)
 +linkmap_add_obj(Obj_Entry *obj)
  {
      struct link_map *l = &obj->linkmap;
 -    struct link_map *prev;
  
 -    obj->linkmap.l_name = obj->path;
 -    obj->linkmap.l_addr = obj->mapbase;
 -    obj->linkmap.l_ld = obj->dynamic;
 +    l->l_name = obj->path;
 +    l->l_addr = obj->mapbase;
 +    l->l_ld = obj->dynamic;
  #ifdef __mips__
      /* GDB needs load offset on MIPS to use the symbols */
 -    obj->linkmap.l_offs = obj->relocbase;
 +    l->l_offs = obj->relocbase;
  #endif
  
 +    linkmap_add_map(l);
 +}
 +
 +static void
 +linkmap_add_map(struct link_map *l)
 +{
 +    struct link_map *prev;
 +
      if (r_debug.r_map == NULL) {
  	r_debug.r_map = l;
  	return;
 @@ -3464,10 +3473,14 @@
  }
  
  static void
 -linkmap_delete(Obj_Entry *obj)
 +linkmap_delete_obj(Obj_Entry *obj)
  {
 -    struct link_map *l = &obj->linkmap;
 +    linkmap_delete_map(&obj->linkmap);
 +}
  
 +static void
 +linkmap_delete_map(struct link_map *l)
 +{
      if (l->l_prev == NULL) {
  	if ((r_debug.r_map = l->l_next) != NULL)
  	    l->l_next->l_prev = NULL;
 @@ -4092,7 +4105,7 @@
  	    dbg("unloading \"%s\"", obj->path);
  	    unload_filtees(root);
  	    munmap(obj->mapbase, obj->mapsize);
 -	    linkmap_delete(obj);
 +	    linkmap_delete_obj(obj);
  	    *linkp = obj->next;
  	    obj_count--;
  	    obj_free(obj);
 @@ -4809,6 +4822,58 @@
  int _thread_autoinit_dummy_decl = 1;
  
  /*
 + * Support for an alternative loader
 + */
 +
 +void
 +r_debug_add(struct link_map *m)
 +{
 +	RtldLockState lockstate;
 +	wlock_acquire(rtld_bind_lock, &lockstate);
 +	GDB_STATE(RT_ADD,NULL);
 +	linkmap_add_map(m);
 +	GDB_STATE(RT_CONSISTENT, m)
 +	lock_release(rtld_bind_lock, &lockstate);
 +}
 +
 +void
 +r_debug_delete(struct link_map *m)
 +{
 +	RtldLockState lockstate;
 +	wlock_acquire(rtld_bind_lock, &lockstate);
 +	GDB_STATE(RT_DELETE, m);
 +	linkmap_delete_map(m);
 +	GDB_STATE(RT_CONSISTENT, NULL);
 +	lock_release(rtld_bind_lock, &lockstate);
 +}
 +
 +int
 +r_debug_iterate(int wr, int (*callback)(struct link_map *, void *), void *param)
 +{
 +	struct link_map *m;
 +	int error = 0;
 +	RtldLockState lockstate;
 +
 +	if (wr) {
 +		wlock_acquire(rtld_bind_lock, &lockstate);
 +	} else {
 +		rlock_acquire(rtld_bind_lock, &lockstate);
 +	}
 +
 +	/*
 +	 * Iterate while callback returns zero
 +	 */
 +	for (m = r_debug.r_map;
 +	     m != NULL && (error = callback(m, param)) == 0;
 +	     m = m->l_next)
 +	     ;
 +
 +	lock_release(rtld_bind_lock, &lockstate);
 +
 +	return error;
 +}
 +
 +/*
   * No unresolved symbols for rtld.
   */
  void
 Index: sys/sys/link_elf.h
 ===================================================================
 --- sys/sys/link_elf.h	(revision 260894)
 +++ sys/sys/link_elf.h	(working copy)
 @@ -94,6 +94,9 @@
  extern int dl_iterate_phdr(__dl_iterate_hdr_callback, void *);
  int _rtld_addr_phdr(const void *, struct dl_phdr_info *);
  int _rtld_get_stack_prot(void);
 +void r_debug_add(struct link_map *);
 +void r_debug_delete(struct link_map *);
 +int r_debug_iterate(int, int (*callback)(struct link_map *, void *), void *);
  
  __END_DECLS
  
 
 --------------010107090807030709030204--
>Unformatted:
