rtld-elf: Sync with FreeBSD
authorJohn Marino <draco@marino.st>
Wed, 13 Apr 2011 19:20:44 +0000 (21:20 +0200)
committerJohn Marino <draco@marino.st>
Thu, 28 Apr 2011 20:02:07 +0000 (22:02 +0200)
The DragonFly run-time linker receives its first upgrade since TLS was
added.  Highlights include improvements to dl functionality:

dlvsym
dl_iterate_phdr
_rtld_addr_phdr
improved dlfunct

Improved security for dangerous LD environment variables were added.
Several bugs were fixed.
libmap.conf functionality was added.
utrace/ktrace support added.
Improved atexit and cxa_atexit finalization.
ELF symbol versioning using gnu semantics.
ldd and kdump improvments
significant man page updates
dynamic token expansion functionlity added.
new locking mechanism
Support for env var LD_ELF_HINTS_PATH
Support for RTLD_NODELETE and RTLD_NOLOAD flags for dlopen
dlfunc moved from libc to rtld

The next GCC upgrade will take advantage of this rtld upgrade in order
to improve exception handling.  DragonFly has never used the shared
libgcc_s which has impeded (or broke?) C++ exception handling.

This commit syncs rtld-elf to the FreeBSD cerca 16 DEC 2010.  However,
bug fixes between then and 25 March 2011 have been included, but major
functionality changes from the ELF Filter support on 25 DEC 2010 onwards
has been excluded.

52 files changed:
include/dlfcn.h
include/link.h
include/paths.h
lib/libc/gen/Makefile.inc
lib/libc/gen/dl_iterate_phdr.3 [new file with mode: 0644]
lib/libc/gen/dladdr.3
lib/libc/gen/dlclose.3 [new file with mode: 0644]
lib/libc/gen/dlerror.3 [new file with mode: 0644]
lib/libc/gen/dlfcn.3 [new file with mode: 0644]
lib/libc/gen/dlfcn.c
lib/libc/gen/dlfunc.c [deleted file]
lib/libc/gen/dlinfo.3
lib/libc/gen/dlopen.3
lib/libc/gen/dlsym.3 [new file with mode: 0644]
lib/libc/gen/dlvsym.3 [new file with mode: 0644]
lib/libc/gen/elf_utils.c [new file with mode: 0644]
lib/libc/include/libc_private.h
lib/libc/stdlib/atexit.c
lib/libthread_xu/pthread.map
lib/libthread_xu/thread/thr_fork.c
lib/libthread_xu/thread/thr_private.h
libexec/rtld-elf/Makefile
libexec/rtld-elf/debug.c
libexec/rtld-elf/debug.h
libexec/rtld-elf/i386/lockdflt.c [deleted file]
libexec/rtld-elf/i386/reloc.c
libexec/rtld-elf/i386/rtld_machdep.h
libexec/rtld-elf/i386/rtld_start.S
libexec/rtld-elf/libmap.c [new file with mode: 0644]
libexec/rtld-elf/libmap.h [new file with mode: 0644]
libexec/rtld-elf/malloc.c
libexec/rtld-elf/map_object.c
libexec/rtld-elf/rtld.1
libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h
libexec/rtld-elf/rtld_lock.c [new file with mode: 0644]
libexec/rtld-elf/rtld_lock.h [copied from libexec/rtld-elf/debug.h with 52% similarity]
libexec/rtld-elf/x86_64/lockdflt.c [deleted file]
libexec/rtld-elf/x86_64/reloc.c
libexec/rtld-elf/x86_64/rtld_machdep.h
libexec/rtld-elf/x86_64/rtld_start.S
share/man/man5/Makefile
share/man/man5/libmap.conf.5 [new file with mode: 0644]
sys/cpu/i386/include/elf.h
sys/cpu/x86_64/include/elf.h
sys/sys/elf32.h
sys/sys/elf_common.h
sys/sys/elf_generic.h
sys/sys/link_elf.h
usr.bin/kdump/kdump.c
usr.bin/ldd/ldd.1
usr.bin/ldd/ldd.c

index d2a4f9f..c2a88d6 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 1994
  *     The Regents of the University of California.  All rights reserved.
  *
  * 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
+ * 3. 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.
  *
@@ -30,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/include/dlfcn.h,v 1.10.2.3 2003/02/20 20:42:45 kan Exp $
+ * $FreeBSD: src/include/dlfcn.h,v 1.24 2010/03/24 15:59:51 gahr Exp $
  */
 
 #ifndef _DLFCN_H_
@@ -48,6 +44,8 @@
 #define        RTLD_GLOBAL     0x100   /* Make symbols globally available. */
 #define        RTLD_LOCAL      0       /* Opposite of RTLD_GLOBAL, and the default. */
 #define        RTLD_TRACE      0x200   /* Trace loaded objects and exit. */
+#define        RTLD_NODELETE   0x01000 /* Do not remove members. */
+#define        RTLD_NOLOAD     0x02000 /* Do not load if not already loaded. */
 
 /*
  * Request arguments for dlinfo().
@@ -56,6 +54,7 @@
 #define        RTLD_DI_SERINFO         4       /* Obtain search path info. */
 #define        RTLD_DI_SERINFOSIZE     5       /*  ... query for required space. */
 #define        RTLD_DI_ORIGIN          6       /* Obtain object origin */
+#define        RTLD_DI_MAX             RTLD_DI_ORIGIN
 
 /*
  * Special handle arguments for dlsym()/dlinfo().
@@ -113,7 +112,7 @@ typedef void (*dlfunc_t)(struct __dlfunc_arg);
 __BEGIN_DECLS
 /* XSI functions first. */
 int             dlclose(void *);
-const char     *dlerror(void);
+char           *dlerror(void);
 void           *dlopen(const char *, int);
 void           *dlsym(void * __restrict, const char * __restrict);
 
@@ -121,9 +120,8 @@ void                *dlsym(void * __restrict, const char * __restrict);
 int             dladdr(const void * __restrict, Dl_info * __restrict);
 dlfunc_t        dlfunc(void * __restrict, const char * __restrict);
 int             dlinfo(void * __restrict, int, void * __restrict);
-void            dllockinit(void *, void *(*)(void *), void (*)(void *),
-                           void (*)(void *), void (*)(void *),
-                           void (*)(void *), void (*)(void *));
+void           *dlvsym(void * __restrict, const char * __restrict,
+                   const char * __restrict);
 #endif /* __BSD_VISIBLE */
 __END_DECLS
 
index d6269e9..bb1c737 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/include/link.h,v 1.20.2.2 2003/02/20 20:42:45 kan Exp $
- * $DragonFly: src/include/link.h,v 1.3 2003/11/14 01:01:43 dillon Exp $
+ * $FreeBSD: src/include/link.h,v 1.25 2002/09/17 01:48:50 peter Exp $
  */
 
-/*
- * RRS section definitions.
- *
- * The layout of some data structures defined in this header file is
- * such that we can provide compatibility with the SunOS 4.x shared
- * library scheme.
- */
-
-#ifndef _LINK_H_
-#define _LINK_H_
-
-#if (defined(FREEBSD_ELF) || defined(__ELF__)) && !defined(FREEBSD_AOUT)
-
-#include <sys/types.h>
-
-/*
- * Flags that describe the origin of the entries in Dl_serinfo.
- * SunOS has these in <sys/link.h>, we follow the suit.
- */
-#define        LA_SER_ORIG     0x01    /* original (needed) name */
-#define        LA_SER_LIBPATH  0x02    /* LD_LIBRARY_PATH entry prepended */
-#define        LA_SER_RUNPATH  0x04    /* runpath entry prepended */
-#define        LA_SER_CONFIG   0x08    /* configuration entry prepended */
-#define        LA_SER_DEFAULT  0x40    /* default path prepended */
-#define        LA_SER_SECURE   0x80    /* default (secure) path prepended */
-
-typedef struct link_map {
-       caddr_t         l_addr;                 /* Base Address of library */
-#ifdef __mips__
-       caddr_t         l_offs;                 /* Load Offset of library */
-#endif
-       const char      *l_name;                /* Absolute Path to Library */
-       const void      *l_ld;                  /* Pointer to .dynamic in memory */
-       struct link_map *l_next, *l_prev;       /* linked list of of mapped libs */
-} Link_map;
-
-struct r_debug {
-       int             r_version;              /* not used */
-       struct link_map *r_map;                 /* list of loaded images */
-       void            (*r_brk)(struct r_debug *, struct link_map *);
-                                               /* pointer to break point */
-       enum {
-           RT_CONSISTENT,                      /* things are stable */
-           RT_ADD,                             /* adding a shared library */
-           RT_DELETE                           /* removing a shared library */
-       }               r_state;
-};
-
-#else /* !__ELF__ */
-
-struct dl_info;
-
-/*
- * A `Shared Object Descriptor' describes a shared object that is needed
- * to complete the link edit process of the object containing it.
- * A list of such objects (chained through `sod_next') is pointed at
- * by `sdt_sods' in the section_dispatch_table structure.
- */
-
-struct sod {   /* Shared Object Descriptor */
-       long    sod_name;               /* name (relative to load address) */
-       u_int   sod_library  : 1,       /* Searched for by library rules */
-               sod_reserved : 31;
-       short   sod_major;              /* major version number */
-       short   sod_minor;              /* minor version number */
-       long    sod_next;               /* next sod */
-};
-
-/*
- * `Shared Object Map's are used by the run-time link editor (ld.so) to
- * keep track of all shared objects loaded into a process' address space.
- * These structures are only used at run-time and do not occur within
- * the text or data segment of an executable or shared library.
- */
-struct so_map {                /* Shared Object Map */
-       caddr_t         som_addr;       /* Address at which object mapped */
-       char            *som_path;      /* Path to mmap'ed file */
-       struct so_map   *som_next;      /* Next map in chain */
-       struct sod      *som_sod;       /* Sod responsible for this map */
-       caddr_t         som_sodbase;    /* Base address of this sod */
-       u_int           som_write : 1;  /* Text is currently writable */
-       struct _dynamic *som_dynamic;   /* _dynamic structure */
-       caddr_t         som_spd;        /* Private data */
-};
-
-/*
- * Symbol description with size. This is simply an `nlist' with
- * one field (nz_size) added.
- * Used to convey size information on items in the data segment
- * of shared objects. An array of these live in the shared object's
- * text segment and is addressed by the `sdt_nzlist' field.
- */
-struct nzlist {
-       struct nlist    nlist;
-       u_long          nz_size;
-};
-
-#define nz_un          nlist.n_un
-#define nz_strx                nlist.n_un.n_strx
-#define nz_name                nlist.n_un.n_name
-#define nz_type                nlist.n_type
-#define nz_value       nlist.n_value
-#define nz_desc                nlist.n_desc
-#define nz_other       nlist.n_other
-
-/*
- * The `section_dispatch_table' structure contains offsets to various data
- * structures needed to do run-time relocation.
- */
-struct section_dispatch_table {
-       struct so_map *sdt_loaded;      /* List of loaded objects */
-       long    sdt_sods;               /* List of shared objects descriptors */
-       long    sdt_paths;              /* Library search paths */
-       long    sdt_got;                /* Global offset table */
-       long    sdt_plt;                /* Procedure linkage table */
-       long    sdt_rel;                /* Relocation table */
-       long    sdt_hash;               /* Symbol hash table */
-       long    sdt_nzlist;             /* Symbol table itself */
-       long    sdt_filler2;            /* Unused (was: stab_hash) */
-       long    sdt_buckets;            /* Number of hash buckets */
-       long    sdt_strings;            /* Symbol strings */
-       long    sdt_str_sz;             /* Size of symbol strings */
-       long    sdt_text_sz;            /* Size of text area */
-       long    sdt_plt_sz;             /* Size of procedure linkage table */
-};
-
-/*
- * RRS symbol hash table, addressed by `sdt_hash' in section_dispatch_table.
- * Used to quickly lookup symbols of the shared object by hashing
- * on the symbol's name. `rh_symbolnum' is the index of the symbol
- * in the shared object's symbol list (`sdt_nzlist'), `rh_next' is
- * the next symbol in the hash bucket (in case of collisions).
- */
-struct rrs_hash {
-       int     rh_symbolnum;           /* Symbol number */
-       int     rh_next;                /* Next hash entry */
-};
-
-/*
- * `rt_symbols' is used to keep track of run-time allocated commons
- * and data items copied from shared objects.
- */
-struct rt_symbol {
-       struct nzlist           *rt_sp;         /* The symbol */
-       struct rt_symbol        *rt_next;       /* Next in linear list */
-       struct rt_symbol        *rt_link;       /* Next in bucket */
-       caddr_t                 rt_srcaddr;     /* Address of "master" copy */
-       struct so_map           *rt_smp;        /* Originating map */
-};
-
-/*
- * Debugger interface structure.
- */
-struct so_debug {
-       int     dd_version;             /* Version # of interface */
-       int     dd_in_debugger;         /* Set when run by debugger */
-       int     dd_sym_loaded;          /* Run-time linking brought more
-                                          symbols into scope */
-       char     *dd_bpt_addr;          /* Address of rtld-generated bpt */
-       int     dd_bpt_shadow;          /* Original contents of bpt */
-       struct rt_symbol *dd_cc;        /* Allocated commons/copied data */
-};
-
-/*
- * Version returned to crt0 from ld.so
- */
-#define LDSO_VERSION_NONE      0       /* FreeBSD2.0, 2.0.5 */
-#define LDSO_VERSION_HAS_DLEXIT        1       /* includes dlexit in ld_entry */
-#define LDSO_VERSION_HAS_DLSYM3        2       /* includes 3-argument dlsym */
-#define LDSO_VERSION_HAS_DLADDR        3       /* includes dladdr in ld_entry */
-
-/*
- * Entry points into ld.so - user interface to the run-time linker.
- * Entries are valid for the given version numbers returned by ld.so
- * to crt0.
- */
-struct ld_entry {
-       void    *(*dlopen) (const char *, int); /* NONE */
-       int     (*dlclose) (void *);            /* NONE */
-       void    *(*dlsym) (void *, const char *);       /* NONE */
-       const char *(*dlerror) (void);          /* NONE */
-       void    (*dlexit) (void);                       /* HAS_DLEXIT */
-       void    *(*dlsym3) (void *, const char *, void *); /* HAS_DLSYM3 */
-       int      (*dladdr) (const void *,
-                               struct dl_info *);      /* HAS_DLADDR */
-};
-
-/*
- * This is the structure pointed at by the __DYNAMIC symbol if an
- * executable requires the attention of the run-time link editor.
- * __DYNAMIC is given the value zero if no run-time linking needs to
- * be done (it is always present in shared objects).
- * The union `d_un' provides for different versions of the dynamic
- * linking mechanism (switched on by `d_version'). The last version
- * used by Sun is 3. We leave some room here and go to version number
- * 8 for NetBSD, the main difference lying in the support for the
- * `nz_list' type of symbols.
- */
-
-struct _dynamic {
-       int             d_version;      /* version # of this interface */
-       struct so_debug *d_debug;
-       union {
-               struct section_dispatch_table *d_sdt;
-       } d_un;
-       struct ld_entry *d_entry;       /* XXX */
-};
-
-#define LD_VERSION_SUN         (3)
-#define LD_VERSION_BSD         (8)
-#define LD_VERSION_NZLIST_P(v) ((v) >= 8)
-
-#define LD_GOT(x)      ((x)->d_un.d_sdt->sdt_got)
-#define LD_PLT(x)      ((x)->d_un.d_sdt->sdt_plt)
-#define LD_REL(x)      ((x)->d_un.d_sdt->sdt_rel)
-#define LD_SYMBOL(x)   ((x)->d_un.d_sdt->sdt_nzlist)
-#define LD_HASH(x)     ((x)->d_un.d_sdt->sdt_hash)
-#define LD_STRINGS(x)  ((x)->d_un.d_sdt->sdt_strings)
-#define LD_NEED(x)     ((x)->d_un.d_sdt->sdt_sods)
-#define LD_BUCKETS(x)  ((x)->d_un.d_sdt->sdt_buckets)
-#define LD_PATHS(x)    ((x)->d_un.d_sdt->sdt_paths)
-
-#define LD_GOTSZ(x)    ((x)->d_un.d_sdt->sdt_plt - (x)->d_un.d_sdt->sdt_got)
-#define LD_RELSZ(x)    ((x)->d_un.d_sdt->sdt_hash - (x)->d_un.d_sdt->sdt_rel)
-#define LD_HASHSZ(x)   ((x)->d_un.d_sdt->sdt_nzlist - (x)->d_un.d_sdt->sdt_hash)
-#define LD_STABSZ(x)   ((x)->d_un.d_sdt->sdt_strings - (x)->d_un.d_sdt->sdt_nzlist)
-#define LD_PLTSZ(x)    ((x)->d_un.d_sdt->sdt_plt_sz)
-#define LD_STRSZ(x)    ((x)->d_un.d_sdt->sdt_str_sz)
-#define LD_TEXTSZ(x)   ((x)->d_un.d_sdt->sdt_text_sz)
-
-/*
- * Interface to ld.so
- */
-struct crt_ldso {
-       int             crt_ba;         /* Base address of ld.so */
-       int             crt_dzfd;       /* "/dev/zero" file descriptor (SunOS) */
-       int             crt_ldfd;       /* ld.so file descriptor */
-       struct _dynamic *crt_dp;        /* Main's __DYNAMIC */
-       char            **crt_ep;       /* environment strings */
-       caddr_t         crt_bp;         /* Breakpoint if run from debugger */
-       char            *crt_prog;      /* Program name (v3) */
-       char            *crt_ldso;      /* Link editor name (v4) */
-       struct ld_entry *crt_ldentry;   /* dl*() access (v4) */
-       char            **crt_argv;     /* argument strings (v5) */
-};
-
-/*
- * Version passed from crt0 to ld.so (1st argument to _rtld()).
- */
-#define CRT_VERSION_SUN                1
-#define CRT_VERSION_BSD_2      2
-#define CRT_VERSION_BSD_3      3
-#define CRT_VERSION_BSD_4      4
-#define CRT_VERSION_BSD_5      5
-
-/*
- * Maximum number of recognized shared object version numbers.
- */
-#define MAXDEWEY       8
-
-/*
- * Header of the hints file.
- */
-struct hints_header {
-       long            hh_magic;
-#define HH_MAGIC       011421044151
-       long            hh_version;     /* Interface version number */
-#define LD_HINTS_VERSION_1     1
-#define LD_HINTS_VERSION_2     2
-       long            hh_hashtab;     /* Location of hash table */
-       long            hh_nbucket;     /* Number of buckets in hashtab */
-       long            hh_strtab;      /* Location of strings */
-       long            hh_strtab_sz;   /* Size of strings */
-       long            hh_ehints;      /* End of hints (max offset in file) */
-       long            hh_dirlist;     /* Colon-separated list of srch dirs */
-};
-
-#define HH_BADMAG(hdr) ((hdr).hh_magic != HH_MAGIC)
-
-/*
- * Hash table element in hints file.
- */
-struct hints_bucket {
-       /* namex and pathx are indices into the string table */
-       int             hi_namex;               /* Library name */
-       int             hi_pathx;               /* Full path */
-       int             hi_dewey[MAXDEWEY];     /* The versions */
-       int             hi_ndewey;              /* Number of version numbers */
-#define hi_major hi_dewey[0]
-#define hi_minor hi_dewey[1]
-       int             hi_next;                /* Next in this bucket */
-};
-
-#define _PATH_LD_HINTS         "/var/run/ld.so.hints"
-
-#endif /* !__ELF__ */
-
-#endif /* _LINK_H_ */
+#include <sys/link_elf.h>
index bdf60eb..68ca75a 100644 (file)
  * 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
+ * 3. 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.
  *
@@ -31,8 +27,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)paths.h     8.1 (Berkeley) 6/2/93
- * $FreeBSD: src/include/paths.h,v 1.9.6.4 2002/07/19 07:53:41 jmallett Exp $
- * $DragonFly: src/include/paths.h,v 1.5 2008/08/30 16:07:58 hasso Exp $
+ * $FreeBSD: src/include/paths.h,v 1.30 2010/02/16 19:39:50 imp Exp $
  */
 
 #ifndef _PATHS_H_
@@ -67,6 +62,7 @@
 #define        _PATH_ICONV     "/usr/share/i18n/iconv"
 #define        _PATH_CSMAPPER  "/usr/share/i18n/csmapper"
 #define        _PATH_KMEM      __SYS_PATH_KMEM
+#define        _PATH_LIBMAP_CONF       "/etc/libmap.conf"
 #define        _PATH_LOCALE    "/usr/share/locale"
 #define        _PATH_LOGIN     "/usr/bin/login"
 #define        _PATH_MAILDIR   "/var/mail"
index 0eef35a..07212b9 100644 (file)
@@ -1,6 +1,5 @@
 #      @(#)Makefile.inc        8.6 (Berkeley) 5/4/95
-# $FreeBSD: src/lib/libc/gen/Makefile.inc,v 1.62.2.19 2003/02/21 13:46:16 phantom Exp $
-# $DragonFly: src/lib/libc/gen/Makefile.inc,v 1.29 2008/10/06 21:01:37 swildner Exp $
+# $FreeBSD: head/lib/libc/gen/Makefile.inc 214680 2010-11-02 17:00:56Z ed $
 
 # machine-independent gen sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/gen ${.CURDIR}/../libc/gen
@@ -9,7 +8,7 @@ SRCS+=  _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
        alarm.c arc4random.c assert.c basename.c \
        clock.c closedir.c confstr.c \
        ctermid.c ctype.c daemon.c devname.c dirname.c disklabel.c disktab.c \
-       dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c exec.c \
+       dlfcn.c drand48.c elf_utils.c erand48.c err.c errlst.c exec.c \
        fdevname.c fmtcheck.c fmtmsg.c fnmatch.c fpclassifyd.c fpclassifyf.c \
        frexp.c fstab.c ftok.c fts.c ftw.c getbootfile.c getbsize.c \
        getcap.c getcwd.c getdevpath.c getdomainname.c \
@@ -52,6 +51,7 @@ MAN+= alarm.3 arc4random.3 clock.3 \
        confstr.3 ctermid.3 ctype.3 daemon.3 \
        devname.3 directory.3 dirname.3 \
        dladdr.3 dlinfo.3 dlopen.3 \
+       dlclose.3 dlerror.3 dlfcn.3 dlsym.3 dlvsym.3 dl_iterate_phdr.3 \
        endutxent.3 err.3 exec.3 \
        fmtcheck.3 fmtmsg.3 fnmatch.3 fpclassify.3 frexp.3 ftok.3 fts.3 ftw.3 \
        getbootfile.3 getbsize.3 getcap.3 getcontext.3 getcwd.3 \
@@ -86,8 +86,8 @@ MLINKS+=ctermid.3 ctermid_r.3
 MLINKS+=directory.3 closedir.3 directory.3 dirfd.3 directory.3 opendir.3 \
        directory.3 readdir.3 directory.3 readdir_r.3 directory.3 rewinddir.3 \
        directory.3 seekdir.3 directory.3 telldir.3 directory.3 fdopendir.3
+MLINKS+=dlsym.3 dlfunc.3
 MLINKS+=devname.3 devname_r.3 devname.3 fdevname.3 devname.3 fdevname_r.3
-MLINKS+=dlopen.3 dlclose.3 dlopen.3 dlerror.3 dlopen.3 dlsym.3
 MLINKS+=endutxent.3 getutxent.3 endutxent.3 getutxid.3 \
        endutxent.3 getutxline.3 endutxent.3 pututxline.3 \
        endutxent.3 setutxent.3 endutxent.3 setutxdb.3
diff --git a/lib/libc/gen/dl_iterate_phdr.3 b/lib/libc/gen/dl_iterate_phdr.3
new file mode 100644 (file)
index 0000000..661be04
--- /dev/null
@@ -0,0 +1,116 @@
+.\"   $NetBSD: dl_iterate_phdr.3,v 1.2 2010/10/16 12:05:48 wiz Exp $
+.\"   $OpenBSD: dl_iterate_phdr.3,v 1.3 2007/05/31 19:19:48 jmc Exp $
+.\"
+.\" Copyright (c) 2005 Mark Kettenis
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd February 10, 2011
+.Os
+.Dt DL_ITERATE_PHDR 3
+.Sh NAME
+.Nm dl_iterate_phdr
+.Nd iterate over program headers
+.Sh SYNOPSIS
+.In link.h
+.Ft int
+.Fn dl_iterate_phdr "int (*callback)(struct dl_phdr_info *, size_t, void*)" "void *data"
+.Sh DESCRIPTION
+The
+.Fn dl_iterate_phdr
+function iterates over all shared objects loaded into a process's
+address space, calling
+.Fa callback
+for each shared object, passing it information about the object's
+program headers and the
+.Fa data
+argument.
+The information about the program headers is passed in a structure
+that is defined as:
+.Bd -literal
+struct dl_phdr_info {
+        Elf_Addr                dlpi_addr;
+        const char             *dlpi_name;
+        const Elf_Phdr         *dlpi_phdr;
+        Elf_Half                dlpi_phnum;
+        unsigned long long int  dlpi_adds;
+        unsigned long long int  dlpi_subs;
+        size_t                  dlpi_tls_modid;
+        void                   *dlpi_tls_data;
+};
+.Ed
+.Pp
+The members of
+.Li struct dl_phdr_info
+have the following meaning:
+.Bl -tag -width XXXdlpi_phdr
+.It Fa dlpi_addr
+The base address at which the shared object is mapped into the address
+space of the calling process.
+.It Fa dlpi_name
+The name of the shared object.
+.It Fa dlpi_phdr
+A pointer to the shared object's program headers.
+.It Fa dlpi_phnum
+The number of program headers in the shared object.
+.It Fa dlpi_adds
+The number of objects added into the main program.
+.It Fa dlpi_subs
+The number of objects removed from the main program.
+.El
+.Pp
+To make it possible for programs to check whether any new members have
+been added, the size of the structure is passed as an argument to
+.Fa callback .
+.Sh EXAMPLE
+The following program displays a list of pathnames of the shared objects it has
+loaded. For each shared object, the program lists the virtual addresses at
+which the object's ELF segments are loaded.
+.Bd -literal
+#include <link.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int
+callback(struct dl_phdr_info *info, size_t size, void *data)
+{
+    int j;
+    printf("name=%s (%d segments)\n", info->dlpi_name,
+        info->dlpi_phnum);
+    for (j = 0; j < info->dlpi_phnum; j++)
+         printf("\t\t header %2d: address=%10p\n", j,
+             (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
+    return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+    dl_iterate_phdr(callback, NULL);
+    exit(EXIT_SUCCESS);
+}
+.Ed
+.Sh RETURN VALUE
+The
+.Fn dl_iterate_phdr
+function returns whatever value was returned by the last call to callback.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ld-elf.so 1 ,
+.Xr dlfcn 3 ,
+.Xr elf 5
+.Sh HISTORY
+The
+.Nm
+function first appeared in
+.Dx 2.9 .
index 71f81cf..21287f8 100644 (file)
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libc/gen/dladdr.3,v 1.3.2.4 2003/03/15 15:11:05 trhodes Exp $
+.\" $FreeBSD: head/lib/libc/gen/dladdr.3 206622 2010-04-14 19:08:06Z uqs $
 .\"
-.Dd February 5, 1998
-.Os
+.Dd February 20, 2011
 .Dt DLADDR 3
+.Os
 .Sh NAME
 .Nm dladdr
 .Nd find the shared object containing a given address
 .Sh LIBRARY
-.Lb libc
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
 .Sh SYNOPSIS
 .In dlfcn.h
 .Ft int
-.Fn dladdr "const void *addr" "Dl_info *info"
+.Fn dladdr "const void * addr" "Dl_info * dlip"
 .Sh DESCRIPTION
 The
 .Fn dladdr
-function queries the dynamic linker for information about the shared object
+function
+queries the dynamic linker for information about the shared object
 containing the address
 .Fa addr .
 The information is returned in the structure specified by
@@ -70,7 +72,8 @@ The value of the symbol returned in
 .Pp
 The
 .Fn dladdr
-function is available only in dynamically linked programs.
+function
+is available only in dynamically linked programs.
 .Sh ERRORS
 If a mapped shared object containing
 .Fa addr
@@ -84,14 +87,15 @@ calling
 On success, a non-zero value is returned.
 .Sh SEE ALSO
 .Xr rtld 1 ,
-.Xr dlopen 3
+.Xr dlfcn 3
 .Sh HISTORY
 The
 .Fn dladdr
 function first appeared in the Solaris operating system.
 .Sh BUGS
 This implementation is bug-compatible with the Solaris
-implementation.  In particular, the following bugs are present:
+implementation.
+In particular, the following bugs are present:
 .Bl -bullet
 .It
 If
@@ -99,12 +103,15 @@ If
 lies in the main executable rather than in a shared library, the
 pathname returned in
 .Va dli_fname
-may not be correct.  The pathname is taken directly from
+may not be correct.
+The pathname is taken directly from
 .Va argv[0]
-of the calling process.  When executing a program specified by its
+of the calling process.
+When executing a program specified by its
 full pathname, most shells set
 .Va argv[0]
-to the pathname.  But this is not required of shells or guaranteed
+to the pathname.
+But this is not required of shells or guaranteed
 by the operating system.
 .It
 If
@@ -113,10 +120,12 @@ is of the form
 .Va &func ,
 where
 .Va func
-is a global function, its value may be an unpleasant surprise.  In
+is a global function, its value may be an unpleasant surprise.
+In
 dynamically linked programs, the address of a global function is
 considered to point to its program linkage table entry, rather than to
-the entry point of the function itself.  This causes most global
+the entry point of the function itself.
+This causes most global
 functions to appear to be defined within the main executable, rather
 than in the shared libraries where the actual code resides.
 .It
diff --git a/lib/libc/gen/dlclose.3 b/lib/libc/gen/dlclose.3
new file mode 100644 (file)
index 0000000..3634a4b
--- /dev/null
@@ -0,0 +1,79 @@
+.\" This source code is a product of Sun Microsystems, Inc. and is provided
+.\" for unrestricted use provided that this legend is included on all tape
+.\" media and as a part of the software program in whole or part.  Users
+.\" may copy or modify this source code without charge, but are not authorized
+.\" to license or distribute it to anyone else except as part of a product or
+.\" program developed by the user.
+.\"
+.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
+.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
+.\" OF SUCH SOURCE CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
+.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  SUN MICROSYSTEMS, INC. DISCLAIMS
+.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
+.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
+.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
+.\"
+.\" This source code is provided with no support and without any obligation on
+.\" the part of Sun Microsystems, Inc. to assist in its use, correction,
+.\" modification or enhancement.
+.\"
+.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+.\" SOURCE CODE OR ANY PART THEREOF.
+.\"
+.\" Sun Microsystems, Inc.
+.\" 2550 Garcia Avenue
+.\" Mountain View, California 94043
+.\"
+.\" Copyright (c) 1991 Sun Microsystems, Inc.
+.\"
+.\" $FreeBSD: release/8.1.0/lib/libc/gen/dlopen.3 205979 2010-03-31 13:51:31Z gahr $
+.\"
+.Dd February 20, 2011
+.Os
+.Dt DLCLOSE 3
+.Sh NAME
+.Nm dlclose
+.Nd unlink shared object from process address space
+.Sh LIBRARY
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft int
+.Fn dlclose "void *handle"
+.Sh DESCRIPTION
+The
+.Fn dlclose
+function
+deletes a reference to the shared object referenced by
+.Fa handle .
+If the reference count drops to 0, the object is removed from the
+address space, and
+.Fa handle
+is rendered invalid.
+Just before removing a shared object in this way, the dynamic linker
+calls the object's
+.Fn _fini
+function, if such a function is defined by the object.
+.Pp
+The object-intrinsic functions
+.Fn _init
+and
+.Fn _fini
+are called with no arguments, and are not expected to return values.
+.Sh RETURN VALUE
+The
+.Fn dlclose
+function
+returns 0 on success, or -1 if an error occurred.
+Whenever an error has been detected, a message detailing it can be
+retrieved via a call to
+.Fn dlerror .
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dlopen 3 ,
+.Xr dlfcn 3 ,
+.Xr dlerror
diff --git a/lib/libc/gen/dlerror.3 b/lib/libc/gen/dlerror.3
new file mode 100644 (file)
index 0000000..80abe64
--- /dev/null
@@ -0,0 +1,77 @@
+.\" This source code is a product of Sun Microsystems, Inc. and is provided
+.\" for unrestricted use provided that this legend is included on all tape
+.\" media and as a part of the software program in whole or part.  Users
+.\" may copy or modify this source code without charge, but are not authorized
+.\" to license or distribute it to anyone else except as part of a product or
+.\" program developed by the user.
+.\"
+.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
+.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
+.\" OF SUCH SOURCE CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
+.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  SUN MICROSYSTEMS, INC. DISCLAIMS
+.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
+.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
+.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
+.\"
+.\" This source code is provided with no support and without any obligation on
+.\" the part of Sun Microsystems, Inc. to assist in its use, correction,
+.\" modification or enhancement.
+.\"
+.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+.\" SOURCE CODE OR ANY PART THEREOF.
+.\"
+.\" Sun Microsystems, Inc.
+.\" 2550 Garcia Avenue
+.\" Mountain View, California 94043
+.\"
+.\" Copyright (c) 1991 Sun Microsystems, Inc.
+.\"
+.\" $FreeBSD: release/8.1.0/lib/libc/gen/dlopen.3 205979 2010-03-31 13:51:31Z gahr $
+.\"
+.Dd February 20, 2011
+.Os
+.Dt DLERROR 3
+.Sh NAME
+.Nm dlerror
+.Nd retrieve dynamic linker error messages
+.Sh LIBRARY
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft char *
+.Fn dlerror "void"
+.Sh DESCRIPTION
+The
+.Fn dlerror
+function
+returns a null-terminated character string describing the last error that
+occurred during a call to
+.Fn dlopen ,
+.Fn dladdr ,
+.Fn dlinfo ,
+.Fn dlsym ,
+.Fn dlvsym ,
+or
+.Fn dlclose .
+If no such error has occurred,
+.Fn dlerror
+returns a null pointer.
+At each call to
+.Fn dlerror ,
+the error indication is reset.
+Thus in the case of two calls
+to
+.Fn dlerror ,
+where the second call follows the first immediately, the second call
+will always return a null pointer.
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dlfcn 3 ,
+.Xr dlopen 3 ,
+.Xr dlclose 3 ,
+.Xr dlsym 3 ,
+.Xr dlvsym 3
diff --git a/lib/libc/gen/dlfcn.3 b/lib/libc/gen/dlfcn.3
new file mode 100644 (file)
index 0000000..ce7d4c7
--- /dev/null
@@ -0,0 +1,103 @@
+.\"    $NetBSD: dlfcn.3,v 1.30 2010/12/24 13:00:24 wiz Exp $
+.\"
+.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Paul Kranenburg.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd March 4, 2011
+.Dt DLFCN 3
+.Os
+.Sh NAME
+.Nm dlopen ,
+.Nm dlclose ,
+.Nm dlinfo ,
+.Nm dladdr ,
+.Nm dlsym ,
+.Nm dlfunc ,
+.Nm dlvsym ,
+.Nm dl_iterate_phdr ,
+.Nm dlerror
+.Nd programmatic interface to the dynamic linker
+.Sh LIBRARY
+(These functions are not in a library.
+They are included in every dynamically linked program automatically.)
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft "void *"
+.Fn dlopen "const char *name" "int mode"
+.Ft "int"
+.Fn dlclose "void *handle"
+.Ft "int"
+.Fn dlinfo "void * handle" "int request" "void * p"
+.Ft "int"
+.Fn dladdr "const void * addr" "Dl_info * dlip"
+.Ft "void *"
+.Fn dlsym "void * handle" "const char * name"
+.Ft dlfunc_t
+.Fn dlfunc "void * handle" "const char * name"
+.Ft "void *"
+.Fn dlvsym "void * handle" "const char * name" "const char * version"
+.Ft "char"
+.Fn dlerror "void"
+.In link.h
+.Ft "int"
+.Fn dl_iterate_phdr "int (*callback)(struct dl_phdr_info *, size_t, void *)" "void * data"
+.Sh DESCRIPTION
+These functions provide an interface to the run-time linker
+.Xr ld-elf.so 1 .
+They allow new shared objects to be loaded into the process' address space
+under program control.
+.Pp
+Please view individual man pages for more information.
+.Pp
+.Bd -literal
+man 3 dlopen
+man 3 dlclose
+man 3 dlinfo
+man 3 dladdr
+man 3 dlsym
+man 3 dlfunc
+man 3 dlvsym
+man 3 dl_iterate_phdr
+man 3 dlerror
+.Ed
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr rtld 1 ,
+.Xr link 5 ,
+.Xr dladdr 3 ,
+.Xr dlinfo 3 ,
+.Xr dlopen 3 ,
+.Xr dlclose 3 ,
+.Xr dlsym 3 ,
+.Xr dlfunc 3 ,
+.Xr dlvsym 3 ,
+.Xr dlerror 3 ,
+.Xr dl_iterate_phr 3
+.Sh HISTORY
+Some of the
+.Nm dl*
+functions first appeared in SunOS 4.
index d7ffc5c..29f98d7 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/gen/dlfcn.c,v 1.6.2.1 2003/02/20 20:42:45 kan Exp $
- * $DragonFly: src/lib/libc/gen/dlfcn.c,v 1.5 2008/06/05 18:06:30 swildner Exp $
+ * $FreeBSD: src/lib/libc/gen/dlfcn.c 217154 2011-01-08 17:13:43Z kib $
  */
 
 #include <dlfcn.h>
+#include <link.h>
 #include <stddef.h>
 
 void   _rtld_error(const char *, ...);
 
-static const char sorry[] = "Service unavailable";
+static char sorry[] = "Service unavailable";
 
 /*
  * For ELF, the dynamic linker directly resolves references to its
@@ -67,7 +67,7 @@ dlclose(void *handle __unused)
 }
 
 #pragma weak dlerror
-const char *
+char *
 dlerror(void)
 {
        return sorry;
@@ -89,6 +89,23 @@ dlsym(void *handle __unused, const char *name __unused)
        return NULL;
 }
 
+#pragma weak dlfunc
+dlfunc_t
+dlfunc(void * handle __unused, const char * name __unused)
+{
+       _rtld_error(sorry);
+       return NULL;
+}
+
+#pragma weak dlvsym
+void *
+dlvsym(void *handle __unused,const char *name __unused,
+    const char *version __unused)
+{
+       _rtld_error(sorry);
+       return NULL;
+}
+
 #pragma weak dlinfo
 int
 dlinfo(void *handle __unused, int request __unused, void *p __unused)
@@ -96,3 +113,21 @@ dlinfo(void *handle __unused, int request __unused, void *p __unused)
        _rtld_error(sorry);
        return 0;
 }
+
+#pragma weak dl_iterate_phdr
+int
+dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
+    void *data)
+{
+       _rtld_error(sorry);
+       return 0;
+}
+
+#pragma weak _rtld_addr_phdr
+int
+_rtld_addr_phdr(const void *addr, struct dl_phdr_info *phdr_info)
+{
+
+       return (0);
+}
+
diff --git a/lib/libc/gen/dlfunc.c b/lib/libc/gen/dlfunc.c
deleted file mode 100644 (file)
index b628de6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This source file is in the public domain.
- * Garrett A. Wollman, 2002-05-28.
- *
- * $FreeBSD: src/lib/libc/gen/dlfunc.c,v 1.3 2002/09/11 05:05:48 mike Exp $
- */
-
-#include <dlfcn.h>
-
-/*
- * Implement the dlfunc() interface, which behaves exactly the same as
- * dlsym() except that it returns a function pointer instead of a data
- * pointer.  This can be used by applications to avoid compiler warnings
- * about undefined behavior, and is intended as prior art for future
- * POSIX standardization.  This function requires that all pointer types
- * have the same representation, which is true on all platforms FreeBSD
- * runs on, but is not guaranteed by the C standard.
- */
-dlfunc_t
-dlfunc(void * __restrict handle, const char * __restrict symbol)
-{
-       union {
-               void *d;
-               dlfunc_t f;
-       } rv;
-
-       rv.d = dlsym(handle, symbol);
-       return (rv.f);
-}
index 831b782..dc844f0 100644 (file)
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libc/gen/dlinfo.3,v 1.3.2.1 2003/02/20 20:42:45 kan Exp $
-.\" $DragonFly: src/lib/libc/gen/dlinfo.3,v 1.13 2008/05/02 02:05:03 swildner Exp $
+.\" $FreeBSD: head/lib/libc/gen/dlinfo.3 206622 2010-04-14 19:08:06Z uqs $
 .\"
-.Dd February 14, 2003
-.Os
+.Dd February 20, 2011
 .Dt DLINFO 3
+.Os
 .Sh NAME
 .Nm dlinfo
 .Nd information about dynamically loaded object
 .Sh LIBRARY
-.Lb libc
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
 .Sh SYNOPSIS
 .In link.h
 .In dlfcn.h
 .Ft int
-.Fn dlinfo "void * __restrict handle" "int request" "void * __restrict p"
+.Fn dlinfo "void * handle" "int request" "void * p"
 .Sh DESCRIPTION
 The
 .Fn dlinfo
@@ -51,163 +51,175 @@ argument depend on value of the
 .Fa request
 argument provided by caller.
 .Pp
-A
+The
 .Fa handle
-argument is either the value returned from a
-.Fn dlopen
+argument is either the value returned from the
+.Xr dlopen 3
 function call or special handle
 .Dv RTLD_SELF .
-If handle is the value returned from
-.Fn dlopen
-call, the information returned by the
+If
+.Fa handle
+is the value returned from
+.Xr dlopen 3 ,
+the information returned by the
 .Fn dlinfo
-function is pertains the specified object.
+function pertains to the specified object.
 If handle is the special handle
 .Dv RTLD_SELF ,
 the information returned pertains to the caller itself.
 .Pp
-The following are possible values for
+Possible values for the
 .Fa request
-argument to be passed into
-.Fn dlinfo :
-.Bl -tag -width Ds
+argument are:
+.Bl -tag -width indent
 .It Dv RTLD_DI_LINKMAP
-Retrieve the Link_map (or
-.Ft struct link_map )
-structure pointer for
-.Fa handle
-specified.
-On successful return the
+Retrieve the
+.Vt Link_map
+.Pq Vt "struct link_map"
+structure pointer for the specified
+.Fa handle .
+On successful return, the
 .Fa p
-argument is filled with pointer to Link_map structure
-.Ft ( Link_map **p )
-describing shared object specified by
+argument is filled with the pointer to the
+.Vt Link_map
+structure
+.Pq Fa "Link_map **p"
+describing a shared object specified by the
 .Fa handle
 argument.
-.Ft Link_map
-structures are maintained as double-linked list by
-.Xr rtld 1
-in same order as
-.Fn dlopen
+The
+.Vt Link_map
+structures are maintained as a doubly linked list by
+.Xr ld.so 1 ,
+in the same order as
+.Xr dlopen 3
 and
-.Fn dlclose
+.Xr dlclose 3
 are called.
 See
-.Sx EXAMPLES
-(Example 1.)
+.Sx EXAMPLES ,
+example 1.
 .Pp
 The
-.Ft Link_map
+.Vt Link_map
 structure is defined in
 .In link.h
 and has the following members:
-.Bd -literal
-  caddr_t         l_addr;    /* Base Address of library */
-  const char      *l_name;   /* Absolute Path to Library */
-  const void      *l_ld;     /* Pointer to .dynamic in memory */
-  struct link_map *l_next,   /* linked list of of mapped libs */
+.Bd -literal -offset indent
+caddr_t         l_addr;    /* Base Address of library */
+const char      *l_name;   /* Absolute Path to Library */
+const void      *l_ld;     /* Pointer to .dynamic in memory */
+struct link_map *l_next,   /* linked list of mapped libs */
                   *l_prev;
 .Ed
-.Bl -tag -width Ds
-.It l_addr
+.Bl -tag -width ".Va l_addr"
+.It Va l_addr
 The base address of the object loaded into memory.
-.It l_name
-The full name of loaded shared object.
-.It l_ld
-The address of dynamic linking information segment
-.Dv ( PT_DYNAMIC )
+.It Va l_name
+The full name of the loaded shared object.
+.It Va l_ld
+The address of the dynamic linking information segment
+.Pq Dv PT_DYNAMIC
 loaded into memory.
-.It l_next
-The next Link_map structure on the link-map list.
-.It l_prev
-The previous Link_map structure on the link-map list.
+.It Va l_next
+The next
+.Vt Link_map
+structure on the link-map list.
+.It Va l_prev
+The previous
+.Vt Link_map
+structure on the link-map list.
 .El
 .It Dv RTLD_DI_SERINFO
-Retrieve the library search paths associated with given
+Retrieve the library search paths associated with the given
 .Fa handle
 argument.
 The
 .Fa p
 argument should point to
-.Ft Dl_serinfo
+.Vt Dl_serinfo
 structure buffer
-.Fa ( Dl_serinfo *p ) .
-.Ft Dl_serinfo
-structure must be initialized first with a
+.Pq Fa "Dl_serinfo *p" .
+The
+.Vt Dl_serinfo
+structure must be initialized first with the
 .Dv RTLD_DI_SERINFOSIZE
 request.
 .Pp
 The returned
-.Ft Dl_serinfo
+.Vt Dl_serinfo
 structure contains
-.Fa dls_cnt
-.Ft Dl_serpath
+.Va dls_cnt
+.Vt Dl_serpath
 entries.
 Each entry's
-.Fa dlp_name
+.Va dlp_name
 field points to the search path.
 The corresponding
-.Fa dlp_info
+.Va dlp_info
 field contains one of more flags indicating the origin of the path (see the
 .Dv LA_SER_*
 flags defined in the
 .In link.h
-header file.)
+header file).
 See
-.Sx EXAMPLES
-(Example 2) for usage example.
+.Sx EXAMPLES ,
+example 2, for a usage example.
 .It Dv RTLD_DI_SERINFOSIZE
 Initialize a
-.Ft Dl_serinfo
+.Vt Dl_serinfo
 structure for use in a
 .Dv RTLD_DI_SERINFO
 request.
 Both the
-.Fa dls_cnt
+.Va dls_cnt
 and
-.Fa dls_size
+.Va dls_size
 fields are returned to indicate the number of search paths applicable
 to the handle, and the total size of a
-.Ft Dl_serinfo
+.Vt Dl_serinfo
 buffer required to hold
-.Fa dls_cnt
-.Ft Dl_serpath
+.Va dls_cnt
+.Vt Dl_serpath
 entries and the associated search path strings.
 See
-.Sx EXAMPLES
-(Example 2) for usage example.
-.It Dv RTLD_DI_ORIGIN
+.Sx EXAMPLES ,
+example 2, for a usage example.
+.It Va RTLD_DI_ORIGIN
 Retrieve the origin of the dynamic object associated with the handle.
-On successful return
+On successful return,
 .Fa p
-argument is filled with
-.Ft char
+argument is filled with the
+.Vt char
 pointer
-.Ft ( char *p ) .
+.Pq Fa "char *p" .
 .El
 .Sh RETURN VALUES
+The
 .Fn dlinfo
-returns 0 on success, or -1 if error occurred.
+function returns 0 on success, or \-1 if an error occurred.
 Whenever an error has been detected, a message detailing it can
 be retrieved via a call to
-.Fn dlerror .
+.Xr dlerror 3 .
 .Sh EXAMPLES
 Example 1: Using
 .Fn dlinfo
-to retrieve Link_map structure.
+to retrieve
+.Vt Link_map
+structure.
 .Pp
 The following example shows how dynamic library can detect the list
 of shared libraries loaded after caller's one.
 For simplicity, error checking has been omitted.
-.Bd -literal
-     Link_map *map;
+.Bd -literal -offset indent
+Link_map *map;
 
-     dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
+dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
 
-     while (map != NULL) {
-         printf("%p: %s\en", map->l_addr, map->l_name);
+while (map != NULL) {
+       printf("%p: %s\\n", map->l_addr, map->l_name);
          map = map->l_next;
-     }
+}
 .Ed
 .Pp
 Example 2: Using
@@ -216,48 +228,46 @@ to retrieve the library search paths.
 .Pp
 The following example shows how a dynamic object can inspect the library
 search paths that would be used to locate a simple filename with
-.Fn dlopen .
+.Xr dlopen 3 .
 For simplicity, error checking has been omitted.
-.Bd -literal
-      Dl_serinfo     _info, *info = &_info;
-      Dl_serpath     *path;
-      unsigned int    cnt;
+.Bd -literal -offset indent
+Dl_serinfo      _info, *info = &_info;
+Dl_serpath     *path;
+unsigned int    cnt;
 
-      /* determine search path count and required buffer size */
-      dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info);
+/* determine search path count and required buffer size */
+dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info);
 
-      /* allocate new buffer and initialize */
-      info = malloc(_info.dls_size);
-      info->dls_size = _info.dls_size;
-      info->dls_cnt = _info.dls_cnt;
+/* allocate new buffer and initialize */
+info = malloc(_info.dls_size);
+info->dls_size = _info.dls_size;
+info->dls_cnt = _info.dls_cnt;
 
-      /* obtain sarch path information */
-      dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info);
+/* obtain sarch path information */
+dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info);
 
-      path = &info->dls_serpath[0];
+path = &info->dls_serpath[0];
 
-      for (cnt = 1; cnt <= info->dls_cnt; cnt++, path++) {
-          (void) printf("%2d: %s\en", cnt, path->dls_name);
-      }
+for (cnt = 1; cnt <= info->dls_cnt; cnt++, path++) {
+       (void) printf("%2d: %s\\n", cnt, path->dls_name);
+}
 .Ed
 .Sh SEE ALSO
 .Xr rtld 1 ,
-.Xr dladdr 3 ,
-.Xr dlopen 3 ,
-.Xr dlsym 3
+.Xr dlfcn 3
 .Sh HISTORY
 The
 .Fn dlinfo
 function first appeared in the Solaris operating system.
 In
-.Fx
+.Fx ,
 it first appeared in
 .Fx 4.8 .
 .Sh AUTHORS
 .An -nosplit
 The
 .Fx
-implementation of
+implementation of the
 .Fn dlinfo
 function was originally written by
 .An Alexey Zelkin
index 26c0648..5b06a7a 100644 (file)
 .\" Copyright (c) 1991 Sun Microsystems, Inc.
 .\"
 .\" @(#) dlopen.3 1.6 90/01/31 SMI
-.\" $FreeBSD: src/lib/libc/gen/dlopen.3,v 1.8.2.10 2003/03/15 15:11:05 trhodes Exp $
-.\" $DragonFly: src/lib/libc/gen/dlopen.3,v 1.2 2003/06/17 04:26:42 dillon Exp $
+.\" $FreeBSD: head/lib/libc/gen/dlopen.3 211397 2010-08-16 15:18:30Z joel $
 .\"
-.Dd September 24, 1989
-.Os
+.Dd February 20, 2011
 .Dt DLOPEN 3
+.Os
 .Sh NAME
-.Nm dlopen ,
-.Nm dlsym ,
-.Nm dlerror ,
-.Nm dlclose
-.Nd programmatic interface to the dynamic linker
+.Nm dlopen
+.Nd returns handle to dynamically loaded shared object
 .Sh LIBRARY
-.Lb libc
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
 .Sh SYNOPSIS
 .In dlfcn.h
 .Ft void *
-.Fn dlopen "const char *path" "int mode"
-.Ft void *
-.Fn dlsym "void *handle" "const char *symbol"
-.Ft dlfunc_t
-.Fn dlfunc "void *handle" "const char *symbol"
-.Ft const char *
-.Fn dlerror "void"
-.Ft int
-.Fn dlclose "void *handle"
+.Fn dlopen "const char *name" "int mode"
 .Sh DESCRIPTION
-These functions provide a simple programmatic interface to the services of the
-dynamic linker.
-Operations are provided to add new shared objects to a
-program's address space, to obtain the address bindings of symbols
-defined by such
-objects, and to remove such objects when their use is no longer required.
-.Pp
 The
 .Fn dlopen
 function
 provides access to the shared object in
 .Fa path ,
 returning a descriptor that can be used for later
-references to the object in calls to
-.Fn dlsym
-and
-.Fn dlclose .
+references to the object in calls to other dl functions.
 If
-.Fa path
+.Fa name
 was not in the address space prior to the call to
 .Fn dlopen ,
 it is placed in the address space.
@@ -84,16 +63,16 @@ function
 .Fn _init ,
 if any, is called by the dynamic linker.
 If
-.Fa path
+.Fa name
 has already been placed in the address space in a previous call to
 .Fn dlopen ,
 it is not added a second time, although a reference count of
 .Fn dlopen
 operations on
-.Fa path
+.Fa name
 is maintained.
 A null pointer supplied for
-.Fa path
+.Fa name
 is interpreted as a reference to the main
 executable of the process.
 The
@@ -123,7 +102,7 @@ call to
 One of the following flags may be ORed into the
 .Fa mode
 argument:
-.Bl -tag -width RTLD_GLOBALX
+.Bl -tag -width RTLD_NODELETE
 .It Dv RTLD_GLOBAL
 Symbols from this shared object and its directed acyclic graph (DAG)
 of needed objects will be available for resolving undefined references
@@ -141,193 +120,72 @@ the absolute pathnames of all objects, to standard output.
 With this flag
 .Fn dlopen
 will return to the caller only in the case of error.
-.El
-.Pp
-If
-.Fn dlopen
-fails, it returns a null pointer, and sets an error condition which may
-be interrogated with
-.Fn dlerror .
-.Pp
-The
-.Fn dlsym
-function
-returns the address binding of the symbol described in the null-terminated
-character string
-.Fa symbol ,
-as it occurs in the shared object identified by
-.Fa handle .
-The symbols exported by objects added to the address space by
-.Fn dlopen
-can be accessed only through calls to
-.Fn dlsym .
-Such symbols do not supersede any definition of those symbols already present
-in the address space when the object is loaded, nor are they available to
-satisfy normal dynamic linking references.
-.Pp
-If
-.Fn dlsym
-is called with the special
-.Fa handle
-.Dv NULL ,
-it is interpreted as a reference to the executable or shared object
-from which the call
-is being made.
-Thus a shared object can reference its own symbols.
-.Pp
-If
-.Fn dlsym
-is called with the special
-.Fa handle
-.Dv RTLD_DEFAULT ,
-the search for the symbol follows the algorithm used for resolving
-undefined symbols when objects are loaded.
-The objects searched are
-as follows, in the given order:
-.Bl -enum
-.It
-The referencing object itself (or the object from which the call to
-.Fn dlsym
-is made), if that object was linked using the
-.Fl Wsymbolic
-option to
+.It Dv RTLD_NODELETE
+Prevents unload of the loaded object on
+.Fn dlclose .
+The same behaviour may be requested by
+.Fl "z nodelete"
+option of the static linker
 .Xr ld 1 .
-.It
-All objects loaded at program start-up.
-.It
-All objects loaded via
-.Fn dlopen
-which are in needed-object DAGs that also contain the referencing object.
-.It
-All objects loaded via
-.Fn dlopen
-with the
-.Dv RTLD_GLOBAL
-flag set in the
-.Fa mode
-argument.
+.It Dv RTLD_NOLOAD
+Ony return valid handle for the object if it is already loaded in
+the process address space, otherwise
+.Dv NULL
+is returned.
+Other mode flags may be specified, which will be applied for promotion
+for the found object.
 .El
-.Pp
-If
-.Fn dlsym
-is called with the special
-.Fa handle
-.Dv RTLD_NEXT ,
-then the search for the symbol is limited to the shared objects
-which were loaded after the one issuing the call to
-.Fn dlsym .
-Thus, if the function is called from the main program, all
-the shared libraries are searched.
-If it is called from a shared library, all subsequent shared
-libraries are searched.
-.Dv RTLD_NEXT
-is useful for implementing wrappers around library functions.
-For example, a wrapper function
-.Fn getpid
-could access the
-.Dq real
-.Fn getpid
-with
-.Li dlsym(RTLD_NEXT, \&"getpid\&") .
-.Pp
-If
-.Fn dlsym
-is called with the special
-.Fa handle
-.Dv RTLD_SELF ,
-then the search for the symbol is limited to the shared object
-issuing the call to
-.Fn dlsym
-and those shared objects which were loaded after it.
-.Pp
-The
-.Fn dlsym
-function
-returns a null pointer if the symbol cannot be found, and sets an error
-condition which may be queried with
-.Fn dlerror .
-.Pp
-The
-.Fn dlerror
-function
-returns a null-terminated character string describing the last error that
-occurred during a call to
-.Fn dlopen ,
-.Fn dladdr ,
-.Fn dlinfo ,
-.Fn dlsym ,
-or
-.Fn dlclose .
-If no such error has occurred,
-.Fn dlerror
-returns a null pointer.
-At each call to
-.Fn dlerror ,
-the error indication is reset.
-Thus in the case of two calls
-to
-.Fn dlerror ,
-where the second call follows the first immediately, the second call
-will always return a null pointer.
-.Pp
-The
-.Fn dlclose
-function
-deletes a reference to the shared object referenced by
-.Fa handle .
-If the reference count drops to 0, the object is removed from the
-address space, and
-.Fa handle
-is rendered invalid.
-Just before removing a shared object in this way, the dynamic linker
-calls the object's
-.Fn _fini
-function, if such a function is defined by the object.
-If
-.Fn dlclose
-is successful, it returns a value of 0.
-Otherwise it returns -1, and sets an error condition that can be
-interrogated with
-.Fn dlerror .
-.Pp
-The object-intrinsic functions
-.Fn _init
-and
-.Fn _fini
-are called with no arguments, and are not expected to return values.
-.Sh NOTES
-ELF executables need to be linked
-using the
-.Fl export-dynamic
-option to
-.Xr ld 1
-for symbols defined in the executable to become visible to
-.Fn dlsym .
-.Pp
-In previous implementations, it was necessary to prepend an underscore
-to all external symbols in order to gain symbol
-compatibility with object code compiled from the C language.
-This is
-still the case when using the (obsolete)
-.Fl aout
-option to the C language compiler.
-.Sh ERRORS
+.Sh RETURN VALUE
 The
 .Fn dlopen
-and
-.Fn dlsym
-functions
-return a null pointer in the event of errors.
-The
-.Fn dlclose
 function
-returns 0 on success, or -1 if an error occurred.
+returns a null pointer in the event of an error.
+The
 Whenever an error has been detected, a message detailing it can be
 retrieved via a call to
 .Fn dlerror .
+.Sh EXAMPLE
+The following program will open any shared gcc library found
+and display the directory in which it was found using the
+dfinfo function.
+.Bd -literal
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char *argv[])
+{
+    void *handle;
+    int   result;
+    char origin[256];
+
+    /* open shared gcc library  */
+    handle = dlopen("libgcc_s.so", RTLD_LAZY);
+    if (!handle) {
+       fprintf (stderr, "%s\n", dlerror ());
+       exit (EXIT_FAILURE);
+    }
+
+    /* get information about the library origin */
+    result = dlinfo (handle, RTLD_DI_ORIGIN, (void *)&origin);
+    if (result < 0) {
+       fprintf (stderr, "%s\n", dlerror ());
+       dlclose (handle);
+       exit (EXIT_FAILURE);
+    }
+
+    /* Display the origin */
+    printf ("libgcc_s origin is %s\\n", &origin[0]);
+    dlclose (handle);
+
+    exit(EXIT_SUCCESS);
+}
+.Ed
 .Sh SEE ALSO
-.Xr ld 1 ,
 .Xr rtld 1 ,
-.Xr dladdr 3 ,
+.Xr dlclose 3 ,
 .Xr dlinfo 3 ,
-.Xr link 5
+.Xr dlerror 3 ,
+.Xr dlfcn 3
+
diff --git a/lib/libc/gen/dlsym.3 b/lib/libc/gen/dlsym.3
new file mode 100644 (file)
index 0000000..8b7c6e0
--- /dev/null
@@ -0,0 +1,224 @@
+.\" This source code is a product of Sun Microsystems, Inc. and is provided
+.\" for unrestricted use provided that this legend is included on all tape
+.\" media and as a part of the software program in whole or part.  Users
+.\" may copy or modify this source code without charge, but are not authorized
+.\" to license or distribute it to anyone else except as part of a product or
+.\" program developed by the user.
+.\"
+.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
+.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
+.\" OF SUCH SOURCE CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
+.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  SUN MICROSYSTEMS, INC. DISCLAIMS
+.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
+.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
+.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
+.\"
+.\" This source code is provided with no support and without any obligation on
+.\" the part of Sun Microsystems, Inc. to assist in its use, correction,
+.\" modification or enhancement.
+.\"
+.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+.\" SOURCE CODE OR ANY PART THEREOF.
+.\"
+.\" Sun Microsystems, Inc.
+.\" 2550 Garcia Avenue
+.\" Mountain View, California 94043
+.\"
+.\" Copyright (c) 1991 Sun Microsystems, Inc.
+.\"
+.\" $FreeBSD: release/8.1.0/lib/libc/gen/dlopen.3 205979 2010-03-31 13:51:31Z gahr $
+.\"
+.Dd March 4, 2011
+.Os
+.Dt DLSYM 3
+.Sh NAME
+.Nm dlsym ,
+.Nm dlfunc
+.Nd shared object symbol lookup function
+.Sh LIBRARY
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft void *
+.Fn dlsym "void * handle" "const char * name"
+.Ft dlfunc_t
+.Fn dlfunc "void * handle" "const char * name"
+.Sh DESCRIPTION
+The
+.Fn dlsym
+function
+returns the address binding of the symbol described in the null-terminated
+character string
+.Fa symbol ,
+as it occurs in the shared object identified by
+.Fa handle .
+The symbols exported by objects added to the address space by
+.Fn dlopen
+can be accessed only through calls to
+.Fn dlsym .
+Such symbols do not supersede any definition of those symbols already present
+in the address space when the object is loaded, nor are they available to
+satisfy normal dynamic linking references.
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv NULL ,
+it is interpreted as a reference to the executable or shared object
+from which the call
+is being made.
+Thus a shared object can reference its own symbols.
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_DEFAULT ,
+the search for the symbol follows the algorithm used for resolving
+undefined symbols when objects are loaded.
+The objects searched are
+as follows, in the given order:
+.Bl -enum
+.It
+The referencing object itself (or the object from which the call to
+.Fn dlsym
+is made), if that object was linked using the
+.Fl Wsymbolic
+option to
+.Xr ld 1 .
+.It
+All objects loaded at program start-up.
+.It
+All objects loaded via
+.Fn dlopen
+with the
+.Dv RTLD_GLOBAL
+flag set in the
+.Fa mode
+argument.
+.It
+All objects loaded via
+.Fn dlopen
+which are in needed-object DAGs that also contain the referencing object.
+.El
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_NEXT ,
+then the search for the symbol is limited to the shared objects
+which were loaded after the one issuing the call to
+.Fn dlsym .
+Thus, if the function is called from the main program, all
+the shared libraries are searched.
+If it is called from a shared library, all subsequent shared
+libraries are searched.
+.Dv RTLD_NEXT
+is useful for implementing wrappers around library functions.
+For example, a wrapper function
+.Fn getpid
+could access the
+.Dq real
+.Fn getpid
+with
+.Li dlsym(RTLD_NEXT, \&"getpid\&") .
+(Actually, the
+.Fn dlfunc
+interface, below, should be used, since
+.Fn getpid
+is a function and not a data object.)
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_SELF ,
+then the search for the symbol is limited to the shared object
+issuing the call to
+.Fn dlsym
+and those shared objects which were loaded after it.
+.Pp
+The
+.Fn dlfunc
+function
+implements all of the behavior of
+.Fn dlsym ,
+but has a return type which can be cast to a function pointer without
+triggering compiler diagnostics.
+(The
+.Fn dlsym
+function
+returns a data pointer; in the C standard, conversions between
+data and function pointer types are undefined.
+Some compilers and
+.Xr lint 1
+utilities warn about such casts.)
+The precise return type of
+.Fn dlfunc
+is unspecified; applications must cast it to an appropriate function pointer
+type.
+.Sh NOTES
+ELF executables need to be linked
+using the
+.Fl export-dynamic
+option to
+.Xr ld 1
+for symbols defined in the executable to become visible to
+.Fn dlsym .
+.Sh RETURN VALUE
+The
+.Fn dlsym
+and
+.Fn dlfunc
+functions
+return the address of the symbol unless the symbol can not be found.
+In this case, they return a null pointer and set an error condition
+which may be queried with
+.Fn dlerror .
+.Sh EXAMPLE
+The following program will obtain a pointer to the cosine function using
+dlsym, and then it will use it to print out the value of cosine (2.0).
+.Bd -literal
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char *argv[])
+{
+    void       *handle;
+    double     (*func_cosine)(double x);
+
+    /* open the system shared math library */
+    handle = dlopen("libm.so", RTLD_LAZY);
+    if (!handle) {
+       fprintf (stderr, "%s\\n", dlerror ());
+       exit (EXIT_FAILURE);
+    }
+
+    /* get pointer to cosine function */
+    func_cosine = dlsym (handle, "cos");
+    if (func_cosine == NULL) {
+       fprintf (stderr, "%s function not found\\n", "cos");
+       dlclose (handle);
+       exit (EXIT_FAILURE);
+    }
+
+    /* Calculate and display the cosine of 2.0 */
+    printf ("cosine of 2.0 = %f\\n", func_cosine(2.0));
+    dlclose (handle);
+
+    exit(EXIT_SUCCESS);
+}
+.Ed
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dlfcn 3 ,
+.Xr dlopen 3 ,
+.Xr dlvsym 3
diff --git a/lib/libc/gen/dlvsym.3 b/lib/libc/gen/dlvsym.3
new file mode 100644 (file)
index 0000000..18b4538
--- /dev/null
@@ -0,0 +1,117 @@
+.\" This source code is a product of Sun Microsystems, Inc. and is provided
+.\" for unrestricted use provided that this legend is included on all tape
+.\" media and as a part of the software program in whole or part.  Users
+.\" may copy or modify this source code without charge, but are not authorized
+.\" to license or distribute it to anyone else except as part of a product or
+.\" program developed by the user.
+.\"
+.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
+.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
+.\" OF SUCH SOURCE CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
+.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  SUN MICROSYSTEMS, INC. DISCLAIMS
+.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
+.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
+.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
+.\"
+.\" This source code is provided with no support and without any obligation on
+.\" the part of Sun Microsystems, Inc. to assist in its use, correction,
+.\" modification or enhancement.
+.\"
+.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+.\" SOURCE CODE OR ANY PART THEREOF.
+.\"
+.\" Sun Microsystems, Inc.
+.\" 2550 Garcia Avenue
+.\" Mountain View, California 94043
+.\"
+.\" Copyright (c) 1991 Sun Microsystems, Inc.
+.\"
+.\" $FreeBSD: head/lib/libc/gen/dlopen.3 211397 2010-08-16 15:18:30Z joel $
+.\"
+.Dd February 20, 2011
+.Os
+.Dt DLVSYM 3
+.Sh NAME
+.Nm dlsym
+.Nd shared object symbol lookup by version function
+.Sh LIBRARY
+This function is not in a library.  It is included in every dynamically linked
+program automatically.
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft void *
+.Fn dlsym "void * handle" "const char * name" "const char * version"
+.Sh DESCRIPTION
+The
+.Fn dlvsym
+function
+does the same as
+.Fn dlsym
+but takes a version string as an additional argument.  Both the name and
+the version must match in order for the symbol to be resolved.
+.Sh NOTES
+ELF executables need to be linked
+using the
+.Fl export-dynamic
+option to
+.Xr ld 1
+for symbols defined in the executable to become visible to
+.Fn dlvsym .
+.Sh RETURN VALUE
+The
+.Fn dlvsym
+function
+returns the address of the symbol unless the symbol can not be found.
+In this case, it returns a null pointer and sets an error condition
+which may be queried with
+.Fn dlerror .
+.Sh EXAMPLE
+The following program will obtain a pointer to the gcc library __adsvsi3
+function using dlvsym specified to version GCC_3.0, and then it will use it
+to print out the sum of 500 + 325.
+.Bd -literal
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char *argv[])
+{
+    void       *handle;
+    int        (*func_sum)(int a, int b);
+
+    /* open the pkgsrc shared gcc library  */
+    handle = dlopen("/usr/pkg/lib/libgcc_s.so", RTLD_LAZY);
+    if (!handle) {
+       fprintf (stderr, "%s\\n", dlerror ());
+       exit (EXIT_FAILURE);
+    }
+
+    /* get pointer to integer sum function */
+    func_sum = dlvsym (handle, "__addvsi3", "GCC_3.0");
+    if (func_sum == NULL) {
+       fprintf (stderr, "function %s version %s not found\\n",
+                "__addvsi3", "GCC_3.0");
+       dlclose (handle);
+       exit (EXIT_FAILURE);
+    }
+
+    /* Calculate and display the sum of 500 + 325 */
+    printf ("500 + 325 = %d\\n", func_sum((int)500, (int)325));
+    dlclose (handle);
+
+    exit(EXIT_SUCCESS);
+}
+.Ed
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dlfcn 3 ,
+.Xr dlsym 3
+.Sh HISTORY
+The
+.Nm
+function first appeared in
+.Dx 2.9 .
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
new file mode 100644 (file)
index 0000000..c578b77
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 Konstantin Belousov <kib@freebsd.org>
+ * All rights reserved.
+ *
+ * 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. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: head/lib/libc/gen/elf_utils.c 217154 2011-01-08 17:13:43Z kib $
+ */
+
+#include <link.h>
+
+int
+__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
+{
+       const Elf_Phdr *ph;
+       int i;
+
+       for (i = 0; i < phdr_info->dlpi_phnum; i++) {
+               ph = &phdr_info->dlpi_phdr[i];
+               if (ph->p_type != PT_LOAD || (ph->p_flags & PF_X) == 0)
+                       continue;
+               if (phdr_info->dlpi_addr + ph->p_vaddr <= (uintptr_t)addr &&
+                   (uintptr_t)addr + sizeof(addr) < phdr_info->dlpi_addr +
+                   ph->p_vaddr + ph->p_memsz)
+                       break;
+       }
+       return (i != phdr_info->dlpi_phnum);
+}
index 6f8a99d..f9c18b8 100644 (file)
  * 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 John Birrell.
- * 4. Neither the name of the author nor the names of any co-contributors
+ * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -29,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/include/libc_private.h,v 1.3 1999/08/27 23:59:47 peter Exp $
+ * $FreeBSD: head/lib/libc/include/libc_private.h 213153 2010-09-25 01:57:47Z davidxu $
  *
  * Private definitions for libc, libc_r and libpthread.
  *
@@ -94,4 +91,7 @@ extern void (*__cleanup)(void);
 int _execvpe(const char *, char * const *, char * const *);
 void _nmalloc_thr_init(void);
 
+struct dl_phdr_info;
+int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
+
 #endif /* _LIBC_PRIVATE_H_ */
index 03f8c2b..0dbd5e5 100644 (file)
  * SUCH DAMAGE.
  *
  * @(#)atexit.c        8.2 (Berkeley) 7/3/94
- * $FreeBSD: src/lib/libc/stdlib/atexit.c,v 1.8 2007/01/09 00:28:09 imp Exp $
- * $DragonFly: src/lib/libc/stdlib/atexit.c,v 1.7 2006/08/03 16:40:46 swildner Exp $
+ * $FreeBSD: head/lib/libc/stdlib/atexit.c 211894 2010-08-27 19:57:17Z kib $
  */
 
 #include "namespace.h"
+#include <link.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -52,6 +52,7 @@ static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 #define _MUTEX_LOCK(x)         if (__isthreaded) _pthread_mutex_lock(x)
 #define _MUTEX_UNLOCK(x)       if (__isthreaded) _pthread_mutex_unlock(x)
+#define _MUTEX_DESTROY(x)      if (__isthreaded) _pthread_mutex_destroy(x)
 
 struct atexit {
        struct atexit *next;                    /* next in list */
@@ -104,7 +105,7 @@ atexit_register(struct atexit_fn *fptr)
        }
        p->fns[p->ind++] = *fptr;
        _MUTEX_UNLOCK(&atexit_mutex);
-       return (0);
+       return 0;
 }
 
 /*
@@ -144,6 +145,9 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso)
        return (error);
 }
 
+#pragma weak __pthread_cxa_finalize
+void __pthread_cxa_finalize(const struct dl_phdr_info *);
+
 /*
  * Call all handlers registered with __cxa_atexit for the shared
  * object owning 'dso'.  Note: if 'dso' is NULL, then all remaining
@@ -152,18 +156,28 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso)
 void
 __cxa_finalize(void *dso)
 {
+       struct dl_phdr_info phdr_info;
        struct atexit *p;
        struct atexit_fn fn;
-       int n;
+       int n, has_phdr;
+
+       if (dso != NULL)
+               has_phdr = _rtld_addr_phdr(dso, &phdr_info);
+       else
+               has_phdr = 0;
 
        _MUTEX_LOCK(&atexit_mutex);
        for (p = __atexit; p; p = p->next) {
                for (n = p->ind; --n >= 0;) {
                        if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
                                continue; /* already been called */
-                       if (dso != NULL && dso != p->fns[n].fn_dso)
-                               continue; /* wrong DSO */
                        fn = p->fns[n];
+                       if (dso != NULL && dso != fn.fn_dso) {
+                               /* wrong DSO ? */
+                               if (!has_phdr || !__elf_phdr_match_addr(
+                                   &phdr_info, fn.fn_ptr.cxa_func))
+                                       continue;
+                       }
                        /*
                          Mark entry to indicate that this particular handler
                          has already been called.
@@ -180,4 +194,9 @@ __cxa_finalize(void *dso)
                }
        }
        _MUTEX_UNLOCK(&atexit_mutex);
+       if (dso == NULL)
+               _MUTEX_DESTROY(&atexit_mutex);
+
+       if (has_phdr && &__pthread_cxa_finalize != NULL)
+               __pthread_cxa_finalize(&phdr_info);
 }
index 633316a..b89954f 100644 (file)
@@ -1,5 +1,4 @@
-# $FreeBSD: src/lib/libpthread/pthread.map,v 1.13 2004/09/26 06:50:14 deischen Exp $
-# $DragonFly: src/lib/libthread_xu/pthread.map,v 1.8 2005/10/25 12:14:52 davidxu Exp $
+# $FreeBSD: src/lib/libpthread/pthread.map,v 1.13 2010/10/23 $
 
 LIBTHREAD_1_0 {
 global:
@@ -15,6 +14,7 @@ global:
        __poll;
        __pthread_cond_timedwait;
        __pthread_cond_wait;
+       __pthread_cxa_finalize;
        __pthread_mutex_init;
        __pthread_mutex_lock;
        __pthread_mutex_trylock;
index cdacc3d..0bbd477 100644 (file)
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libpthread/thread/thr_atfork.c,v 1.1 2003/11/05 03:42:10 davidxu Exp $
+ * $FreeBSD: head/lib/libthr/thread/thr_fork.c 213096 2010-08-23 $
  */
 
 /*
  * 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 John Birrell.
- * 4. Neither the name of the author nor the names of any co-contributors
+ * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libpthread/thread/thr_fork.c,v 1.34 2003/11/05 18:18:45 deischen Exp $
- * $DragonFly: src/lib/libthread_xu/thread/thr_fork.c,v 1.6 2006/04/06 13:03:09 davidxu Exp $
  */
 
 #include "namespace.h"
 #include <machine/tls.h>
 
 #include <errno.h>
+#include <link.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -102,6 +98,27 @@ _pthread_atfork(void (*prepare)(void), void (*parent)(void),
        return (0);
 }
 
+void
+__pthread_cxa_finalize(struct dl_phdr_info *phdr_info)
+{
+       struct pthread *curthread;
+       struct pthread_atfork *af, *af1;
+
+       _thr_check_init();
+
+       curthread = tls_get_curthread();
+       THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+       TAILQ_FOREACH_MUTABLE(af, &_thr_atfork_list, qe, af1) {
+               if (__elf_phdr_match_addr(phdr_info, af->prepare) ||
+                   __elf_phdr_match_addr(phdr_info, af->parent) ||
+                   __elf_phdr_match_addr(phdr_info, af->child)) {
+                       TAILQ_REMOVE(&_thr_atfork_list, af, qe);
+                       free(af);
+               }
+       }
+       THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+}
+
 /*
  * For a while, allow libpthread to work with a libc that doesn't
  * export the malloc lock.
index 307c106..6633085 100644 (file)
@@ -31,8 +31,7 @@
  *
  * Private thread definitions for the uthread kernel.
  *
- * $FreeBSD: src/lib/libpthread/thread/thr_private.h,v 1.120 2004/11/01 10:49:34 davidxu Exp $
- * $DragonFly: src/lib/libthread_xu/thread/thr_private.h,v 1.19 2008/07/15 01:18:53 dillon Exp $
+ * $FreeBSD: head/lib/libthr/thread/thr_private.h 217706 2010-08-23 $
  */
 
 #ifndef _THR_PRIVATE_H
@@ -797,6 +796,9 @@ _thr_check_init(void)
                _libpthread_init(0);
 }
 
+struct dl_phdr_info;
+void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
+
 __END_DECLS
 
 #endif  /* !_THR_PRIVATE_H */
index ffa8413..347aff1 100644 (file)
@@ -1,12 +1,16 @@
 # $FreeBSD: src/libexec/rtld-elf/Makefile,v 1.10.2.6 2002/06/22 17:03:13 jdp Exp $
 
 PROG=          ld-elf.so.2
-SRCS=          rtld_start.S rtld.c lockdflt.c map_object.c malloc.c \
-               xmalloc.c debug.c reloc.c
+SRCS=          rtld_start.S rtld.c rtld_lock.c map_object.c malloc.c \
+               xmalloc.c debug.c reloc.c libmap.c
 MAN=           rtld.1
 WARNS?=                2
 
-CFLAGS+=       -Wall -I${.CURDIR}/${MACHINE_ARCH} -I${.CURDIR} -D__thread=
+# To activate LD_DEBUG functionality, define ENABLE_DEBUG
+# e.g. make -DENABLE_DEBUG
+
+CFLAGS+=       -DIN_RTLD
+CFLAGS+=       -I${.CURDIR}/${MACHINE_ARCH} -I${.CURDIR} -D__thread=
 LDFLAGS+=      -nostdlib -e .rtld_start -Wl,--no-undefined
 INSTALLFLAGS=  -C -b
 .ifndef NOFSCHG
@@ -32,6 +36,10 @@ DPADD=               ${.OBJDIR}/../../lib/libc_rtld/libc_rtld_pic.a
 LDADD=         -L${.OBJDIR}/../../lib/libc_rtld -lc_rtld_pic
 .endif
 
+.ifdef ENABLE_DEBUG
+CFLAGS+=       -DDEBUG
+.endif
+
 dyn_hack.so:
        ${CC} -shared -nostdlib -o dyn_hack.so -x c /dev/null
 
index dd72d80..3a83b66 100644 (file)
@@ -22,8 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/debug.c,v 1.2 1999/08/28 00:10:09 peter Exp $
- * $DragonFly: src/libexec/rtld-elf/debug.c,v 1.4 2005/03/30 00:53:59 joerg Exp $
+ * $FreeBSD: src/libexec/rtld-elf/debug.c,v 1.4 2003/06/19 16:09:18 mdodd Exp $
  */
 
 /*
@@ -39,7 +38,7 @@
 static const char rel_header[] =
     " symbol name               r_info r_offset st_value st_size    address    value\n"
     " ------------------------------------------------------------------------------\n";
-static const char rel_format[] =  " %-25s %6lx %08lx %08lx %7ld %10p %08lx\n";
+static const char rel_format[] =  " %-25s %6lx %08lx %08lx %7d %10p %08lx\n";
 
 int debug = 0;
 
@@ -114,9 +113,9 @@ dump_Elf_Rel (Obj_Entry *obj, const Elf_Rel *rel0, u_long relsize)
         sym = obj->symtab + ELF_R_SYM(rel->r_info);
         printf(rel_format,
                obj->strtab + sym->st_name,
-               (long)rel->r_info, (long)rel->r_offset,
-               (long)sym->st_value, (long)sym->st_size,
-               dstaddr, (long)*dstaddr);
+               (u_long)rel->r_info, (u_long)rel->r_offset,
+               (u_long)sym->st_value, (int)sym->st_size,
+               dstaddr, (u_long)*dstaddr);
     }
     return;
 }
@@ -136,9 +135,9 @@ dump_Elf_Rela (Obj_Entry *obj, const Elf_Rela *rela0, u_long relasize)
         sym = obj->symtab + ELF_R_SYM(rela->r_info);
         printf(rel_format,
                obj->strtab + sym->st_name,
-               (long)rela->r_info, (long)rela->r_offset,
-               (long)sym->st_value, (long)sym->st_size,
-               dstaddr, (long)*dstaddr);
+               (u_long)rela->r_info, (u_long)rela->r_offset,
+               (u_long)sym->st_value, (int)sym->st_size,
+               dstaddr, (u_long)*dstaddr);
     }
     return;
 }
index f02214e..42f3192 100644 (file)
@@ -22,8 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/debug.h,v 1.4 1999/12/27 04:44:01 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/debug.h,v 1.3 2005/05/11 19:47:06 dillon Exp $
+ * $FreeBSD: src/libexec/rtld-elf/debug.h,v 1.7 2006/03/28 18:26:47 des Exp $
  */
 
 /*
@@ -46,15 +45,17 @@ extern void debug_printf(const char *, ...) __printflike(1, 2);
 extern int debug;
 
 #ifdef DEBUG
-#define dbg(format, args...)   debug_printf(format , ## args)
+#define dbg(...)       debug_printf(__VA_ARGS__)
 #else
-#define dbg(format, args...)   ((void) 0)
+#define dbg(...)       ((void) 0)
 #endif
 
+#define _MYNAME        "ld-elf.so.2"
 #define assert(cond)   ((cond) ? (void) 0 :            \
-    (msg("ld-elf.so.2: assert failed: " __FILE__ ":"   \
+    (msg(_MYNAME ": assert failed: " __FILE__ ":"      \
       __XSTRING(__LINE__) "\n"), abort()))
-#define msg(s)         write(1, s, strlen(s))
-#define trace()                msg("ld-elf.so.2: " __XSTRING(__LINE__) "\n")
+#define msg(s)         write(STDOUT_FILENO, s, strlen(s))
+#define trace()                msg(_MYNAME ": " __XSTRING(__LINE__) "\n")
+
 
 #endif /* DEBUG_H */
diff --git a/libexec/rtld-elf/i386/lockdflt.c b/libexec/rtld-elf/i386/lockdflt.c
deleted file mode 100644 (file)
index 046ba68..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*-
- * Copyright 1999, 2000 John D. Polstra.
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD: src/libexec/rtld-elf/i386/lockdflt.c,v 1.5.2.4 2002/07/11 23:52:32 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/lockdflt.c,v 1.3 2007/11/09 19:38:50 hasso Exp $
- */
-
-/*
- * Thread locking implementation for the dynamic linker.
- *
- * We use the "simple, non-scalable reader-preference lock" from:
- *
- *   J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
- *   Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
- *   Principles and Practice of Parallel Programming, April 1991.
- *
- * In this algorithm the lock is a single word.  Its low-order bit is
- * set when a writer holds the lock.  The remaining high-order bits
- * contain a count of readers desiring the lock.  The algorithm requires
- * atomic "compare_and_store" and "add" operations.
- *
- */
-
-#include <setjmp.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "debug.h"
-#include "rtld.h"
-
-#define CACHE_LINE_SIZE                32
-
-#define WAFLAG         0x1     /* A writer holds the lock */
-#define RC_INCR                0x2     /* Adjusts count of readers desiring lock */
-
-typedef struct Struct_Lock {
-       volatile int lock;
-       void *base;
-} Lock;
-
-static sigset_t fullsigmask, oldsigmask;
-
-static inline int
-cmpxchgl(int old, int new, volatile int *m)
-{
-       int result;
-
-       __asm __volatile ("lock; cmpxchgl %2, %0"
-           : "+m"(*m), "=a"(result)
-           : "r"(new), "1"(old)
-           : "cc");
-
-       return result;
-}
-
-static void *
-lock_create(void *context)
-{
-    void *base;
-    char *p;
-    uintptr_t r;
-    Lock *l;
-
-    /*
-     * Arrange for the lock to occupy its own cache line.  First, we
-     * optimistically allocate just a cache line, hoping that malloc
-     * will give us a well-aligned block of memory.  If that doesn't
-     * work, we allocate a larger block and take a well-aligned cache
-     * line from it.
-     */
-    base = xmalloc(CACHE_LINE_SIZE);
-    p = (char *)base;
-    if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
-       free(base);
-       base = xmalloc(2 * CACHE_LINE_SIZE);
-       p = (char *)base;
-       if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
-           p += CACHE_LINE_SIZE - r;
-    }
-    l = (Lock *)p;
-    l->base = base;
-    l->lock = 0;
-    return l;
-}
-
-static void
-lock_destroy(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    free(l->base);
-}
-
-/*
- * Reader/writer locks.
- */
-static void
-rlock_acquire(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, RC_INCR);
-    while (l->lock & WAFLAG)
-           ;   /* Spin */
-}
-
-static void
-wlock_acquire(void *lock)
-{
-    Lock *l = (Lock *)lock;
-    sigset_t tmp_oldsigmask;
-
-    for ( ; ; ) {
-       sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
-       if (cmpxchgl(0, WAFLAG, &l->lock) == 0)
-           break;
-       sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
-    }
-    oldsigmask = tmp_oldsigmask;
-}
-
-static void
-rlock_release(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, -RC_INCR);
-}
-
-static void
-wlock_release(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, -WAFLAG);
-    sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
-}
-
-void
-lockdflt_init(LockInfo *li)
-{
-    li->context = NULL;
-    li->context_destroy = NULL;
-    li->lock_create = lock_create;
-    li->lock_destroy = lock_destroy;
-    li->rlock_acquire = rlock_acquire;
-    li->wlock_acquire = wlock_acquire;
-    li->rlock_release = rlock_release;
-    li->wlock_release = wlock_release;
-    /*
-     * Construct a mask to block all signals except traps which might
-     * conceivably be generated within the dynamic linker itself.
-     */
-    sigfillset(&fullsigmask);
-    sigdelset(&fullsigmask, SIGILL);
-    sigdelset(&fullsigmask, SIGTRAP);
-    sigdelset(&fullsigmask, SIGABRT);
-    sigdelset(&fullsigmask, SIGEMT);
-    sigdelset(&fullsigmask, SIGFPE);
-    sigdelset(&fullsigmask, SIGBUS);
-    sigdelset(&fullsigmask, SIGSEGV);
-    sigdelset(&fullsigmask, SIGSYS);
-}
index b5ed9be..84e22b8 100644 (file)
@@ -22,8 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.6.2.2 2002/06/16 20:02:09 dillon Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.13 2005/05/11 19:47:09 dillon Exp $
+ * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.22 2010/12/25 08:51:20 kib Exp $
  */
 
 /*
@@ -76,6 +75,7 @@ do_copy_relocations(Obj_Entry *dstobj)
            size_t size;
            const void *srcaddr;
            const Elf_Sym *srcsym;
+           const Ver_Entry *ve;
            Obj_Entry *srcobj;
 
            dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
@@ -83,9 +83,10 @@ do_copy_relocations(Obj_Entry *dstobj)
            name = dstobj->strtab + dstsym->st_name;
            hash = elf_hash(name);
            size = dstsym->st_size;
+           ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
 
            for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-               if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
+               if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
                    break;
 
            if (srcobj == NULL) {
@@ -114,20 +115,21 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
 {
        const Elf_Rel *rellim;
        const Elf_Rel *rel;
        SymCache *cache;
-       int bytes = obj->nchains * sizeof(SymCache);
        int r = -1;
 
        /*
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
-       cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-       if (cache == MAP_FAILED)
+       if (obj != obj_rtld) {
+           cache = calloc(obj->nchains, sizeof(SymCache));
+           /* No need to check for NULL here */
+       } else
            cache = NULL;
 
        rellim = (const Elf_Rel *) ((c_caddr_t) obj->rel + obj->relsize);
@@ -303,8 +305,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld __unused)
        }
        r = 0;
 done:
-       if (cache)
-           munmap(cache, bytes);
+       if (cache != NULL)
+           free(cache);
        return(r);
 }
 
@@ -339,7 +341,7 @@ reloc_jmpslots(Obj_Entry *obj)
        return 0;
     rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
     for (rel = obj->pltrel;  rel < rellim;  rel++) {
-       Elf_Addr *where;
+       Elf_Addr *where, target;
        const Elf_Sym *def;
        const Obj_Entry *defobj;
 
@@ -348,7 +350,8 @@ reloc_jmpslots(Obj_Entry *obj)
        def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL);
        if (def == NULL)
            return -1;
-       reloc_jmpslot(where, (Elf_Addr)(defobj->relocbase + def->st_value));
+       target = (Elf_Addr)(defobj->relocbase + def->st_value);
+       reloc_jmpslot(where, target, defobj, obj, rel);
     }
     obj->jmpslots_done = true;
     return 0;
@@ -360,9 +363,12 @@ void *
 ___tls_get_addr(tls_index *ti)
 {
     struct tls_tcb *tcb;
+    Elf_Addr* dtv;
 
     tcb = tls_get_tcb();
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    dtv = (Elf_Addr*)tcb->tcb_dtv;
+
+    return tls_get_addr_common(&dtv, ti->ti_module, ti->ti_offset);
 }
 
 /* Sun ABI */
@@ -370,15 +376,20 @@ void *
 __tls_get_addr(tls_index *ti)
 {
     struct tls_tcb *tcb;
+    Elf_Addr* dtv;
 
     tcb = tls_get_tcb();
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    dtv = (Elf_Addr*)tcb->tcb_dtv;
+
+    return tls_get_addr_common(&dtv, ti->ti_module, ti->ti_offset);
 }
 
 /* Sun ABI */
 void *
 __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
 {
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    Elf_Addr* dtv = (Elf_Addr*)tcb->tcb_dtv;
+
+    return tls_get_addr_common(&dtv, ti->ti_module, ti->ti_offset);
 }
 
index 03f1160..4ce427d 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.3.2.2 2002/07/02 04:10:51 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.7 2005/05/11 19:47:09 dillon Exp $
+ * $FreeBSD: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.13 2011/01/25 21:12:31 kib Exp $
  */
 
 #ifndef RTLD_MACHDEP_H
 #define RTLD_MACHDEP_H 1
 
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+#define CACHE_LINE_SIZE        32
+
+struct Struct_Obj_Entry;
+
 /* Return the address of the .dynamic section in the dynamic linker. */
 #define rtld_dynamic(obj) \
     ((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC))
 
 /* Fixup the jump slot at "where" to transfer control to "target". */
-#define reloc_jmpslot(where, target)                   \
-    do {                                               \
-       dbg("reloc_jmpslot: *%p = %p", (void *)(where), \
-         (void *)(target));                            \
-       (*(Elf_Addr *)(where) = (Elf_Addr)(target));    \
-    } while (0)
-
-static inline void
-atomic_decr_int(volatile int *p)
+static inline Elf_Addr
+reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
+             const struct Struct_Obj_Entry *obj,
+             const struct Struct_Obj_Entry *refobj, const Elf_Rel *rel)
 {
-    __asm __volatile ("lock; decl %0" : "+m"(*p) : : "cc");
+#ifdef dbg
+    dbg("reloc_jmpslot: *%p = %p", (void *)(where),
+       (void *)(target));
+#endif
+    (*(Elf_Addr *)(where) = (Elf_Addr)(target));
+    return target;
 }
 
-static inline void
-atomic_incr_int(volatile int *p)
-{
-    __asm __volatile ("lock; incl %0" : "+m"(*p) : : "cc");
-}
+#define make_function_pointer(def, defobj) \
+       ((defobj)->relocbase + (def)->st_value)
 
-static inline void
-atomic_add_int(volatile int *p, int val)
-{
-    __asm __volatile ("lock; addl %1, %0"
-       : "+m"(*p)
-       : "ri"(val)
-       : "cc");
-}
+#define call_initfini_pointer(obj, target) \
+       (((InitFunc)(target))())
 
 #define round(size, align) \
        (((size) + (align) - 1) & ~((align) - 1))
index b5446ca..4cac006 100644 (file)
@@ -23,7 +23,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/libexec/rtld-elf/i386/rtld_start.S,v 1.3 1999/08/28 00:10:15 peter Exp $
- * $DragonFly: src/libexec/rtld-elf/i386/rtld_start.S,v 1.4 2008/01/08 00:02:04 corecode Exp $
  */
 
        .text
@@ -91,3 +90,5 @@ _rtld_bind_start:
        popf                            # Restore eflags
        leal    4(%esp),%esp            # Discard reloff, do not change eflags
        ret                             # "Return" to target address
+
+       .section .note.GNU-stack,"",%progbits
diff --git a/libexec/rtld-elf/libmap.c b/libexec/rtld-elf/libmap.c
new file mode 100644 (file)
index 0000000..edc759e
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * $FreeBSD: src/libexec/rtld-elf/libmap.c,v 1.15 2006/01/31 06:08:28 peter Exp $
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+
+#include "debug.h"
+#include "rtld.h"
+#include "libmap.h"
+
+#ifndef _PATH_LIBMAP_CONF
+#define        _PATH_LIBMAP_CONF       "/etc/libmap.conf"
+#endif
+
+TAILQ_HEAD(lm_list, lm);
+struct lm {
+       char *f;
+       char *t;
+
+       TAILQ_ENTRY(lm) lm_link;
+};
+
+TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head);
+struct lmp {
+       char *p;
+       enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type;
+       struct lm_list lml;
+       TAILQ_ENTRY(lmp) lmp_link;
+};
+
+static int     lm_count;
+
+static void            lmc_parse       (FILE *);
+static void            lm_add          (const char *, const char *, const char *);
+static void            lm_free         (struct lm_list *);
+static char *          lml_find        (struct lm_list *, const char *);
+static struct lm_list *        lmp_find        (const char *);
+static struct lm_list *        lmp_init        (char *);
+static const char * quickbasename      (const char *);
+static int     readstrfn       (void * cookie, char *buf, int len);
+static int     closestrfn      (void * cookie);
+
+#define        iseol(c)        (((c) == '#') || ((c) == '\0') || \
+                        ((c) == '\n') || ((c) == '\r'))
+
+int
+lm_init (char *libmap_override)
+{
+       FILE    *fp;
+
+       dbg("%s(\"%s\")", __func__, libmap_override);
+
+       TAILQ_INIT(&lmp_head);
+
+       fp = fopen(_PATH_LIBMAP_CONF, "r");
+       if (fp) {
+               lmc_parse(fp);
+               fclose(fp);
+       }
+
+       if (libmap_override) {
+               char    *p;
+               /* do some character replacement to make $LIBMAP look like a
+                  text file, then "open" it with funopen */
+               libmap_override = xstrdup(libmap_override);
+
+               for (p = libmap_override; *p; p++) {
+                       switch (*p) {
+                               case '=':
+                                       *p = ' '; break;
+                               case ',':
+                                       *p = '\n'; break;
+                       }
+               }
+               fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn);
+               if (fp) {
+                       lmc_parse(fp);
+                       fclose(fp);
+               }
+       }
+
+       return (lm_count == 0);
+}
+
+static void
+lmc_parse (FILE *fp)
+{
+       char    *cp;
+       char    *f, *t, *c, *p;
+       char    prog[MAXPATHLEN];
+       char    line[MAXPATHLEN + 2];
+
+       dbg("%s(%p)", __func__, fp);
+
+       p = NULL;
+       while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
+               t = f = c = NULL;
+
+               /* Skip over leading space */
+               while (isspace(*cp)) cp++;
+
+               /* Found a comment or EOL */
+               if (iseol(*cp)) continue;
+
+               /* Found a constraint selector */
+               if (*cp == '[') {
+                       cp++;
+
+                       /* Skip leading space */
+                       while (isspace(*cp)) cp++;
+
+                       /* Found comment, EOL or end of selector */
+                       if  (iseol(*cp) || *cp == ']')
+                               continue;
+
+                       c = cp++;
+                       /* Skip to end of word */
+                       while (!isspace(*cp) && !iseol(*cp) && *cp != ']')
+                               cp++;
+
+                       /* Skip and zero out trailing space */
+                       while (isspace(*cp)) *cp++ = '\0';
+
+                       /* Check if there is a closing brace */
+                       if (*cp != ']') continue;
+
+                       /* Terminate string if there was no trailing space */
+                       *cp++ = '\0';
+
+                       /*
+                        * There should be nothing except whitespace or comment
+                         from this point to the end of the line.
+                        */
+                       while(isspace(*cp)) cp++;
+                       if (!iseol(*cp)) continue;
+
+                       strcpy(prog, c);
+                       p = prog;
+                       continue;
+               }
+
+               /* Parse the 'from' candidate. */
+               f = cp++;
+               while (!isspace(*cp) && !iseol(*cp)) cp++;
+
+               /* Skip and zero out the trailing whitespace */
+               while (isspace(*cp)) *cp++ = '\0';
+
+               /* Found a comment or EOL */
+               if (iseol(*cp)) continue;
+
+               /* Parse 'to' mapping */
+               t = cp++;
+               while (!isspace(*cp) && !iseol(*cp)) cp++;
+
+               /* Skip and zero out the trailing whitespace */
+               while (isspace(*cp)) *cp++ = '\0';
+
+               /* Should be no extra tokens at this point */
+               if (!iseol(*cp)) continue;
+
+               *cp = '\0';
+               lm_add(p, f, t);
+       }
+}
+
+static void
+lm_free (struct lm_list *lml)
+{
+       struct lm *lm;
+
+       dbg("%s(%p)", __func__, lml);
+
+       while (!TAILQ_EMPTY(lml)) {
+               lm = TAILQ_FIRST(lml);
+               TAILQ_REMOVE(lml, lm, lm_link);
+               free(lm->f);
+               free(lm->t);
+               free(lm);
+       }
+       return;
+}
+
+void
+lm_fini (void)
+{
+       struct lmp *lmp;
+
+       dbg("%s()", __func__);
+
+       while (!TAILQ_EMPTY(&lmp_head)) {
+               lmp = TAILQ_FIRST(&lmp_head);
+               TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
+               free(lmp->p);
+               lm_free(&lmp->lml);
+               free(lmp);
+       }
+       return;
+}
+
+static void
+lm_add (const char *p, const char *f, const char *t)
+{
+       struct lm_list *lml;
+       struct lm *lm;
+
+       if (p == NULL)
+               p = "$DEFAULT$";
+
+       dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
+
+       if ((lml = lmp_find(p)) == NULL)
+               lml = lmp_init(xstrdup(p));
+
+       lm = xmalloc(sizeof(struct lm));
+       lm->f = xstrdup(f);
+       lm->t = xstrdup(t);
+       TAILQ_INSERT_HEAD(lml, lm, lm_link);
+       lm_count++;
+}
+
+char *
+lm_find (const char *p, const char *f)
+{
+       struct lm_list *lml;
+       char *t;
+
+       dbg("%s(\"%s\", \"%s\")", __func__, p, f);
+
+       if (p != NULL && (lml = lmp_find(p)) != NULL) {
+               t = lml_find(lml, f);
+               if (t != NULL) {
+                       /*
+                        * Add a global mapping if we have
+                        * a successful constrained match.
+                        */
+                       lm_add(NULL, f, t);
+                       return (t);
+               }
+       }
+       lml = lmp_find("$DEFAULT$");
+       if (lml != NULL)
+               return (lml_find(lml, f));
+       else
+               return (NULL);
+}
+
+static char *
+lml_find (struct lm_list *lmh, const char *f)
+{
+       struct lm *lm;
+
+       dbg("%s(%p, \"%s\")", __func__, lmh, f);
+
+       TAILQ_FOREACH(lm, lmh, lm_link)
+               if (strcmp(f, lm->f) == 0)
+                       return (lm->t);
+       return (NULL);
+}
+
+/* Given an executable name, return a pointer to the translation list or
+   NULL if no matches */
+static struct lm_list *
+lmp_find (const char *n)
+{
+       struct lmp *lmp;
+
+       dbg("%s(\"%s\")", __func__, n);
+
+       TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
+               if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) ||
+                   (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) ||
+                   (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0))
+                       return (&lmp->lml);
+       return (NULL);
+}
+
+static struct lm_list *
+lmp_init (char *n)
+{
+       struct lmp *lmp;
+
+       dbg("%s(\"%s\")", __func__, n);
+
+       lmp = xmalloc(sizeof(struct lmp));
+       lmp->p = n;
+       if (n[strlen(n)-1] == '/')
+               lmp->type = T_DIRECTORY;
+       else if (strchr(n,'/') == NULL)
+               lmp->type = T_BASENAME;
+       else
+               lmp->type = T_EXACT;
+       TAILQ_INIT(&lmp->lml);
+       TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
+
+       return (&lmp->lml);
+}
+
+/* libc basename is overkill.  Return a pointer to the character after the
+   last /, or the original string if there are no slashes. */
+static const char *
+quickbasename (const char *path)
+{
+       const char *p = path;
+       for (; *path; path++) {
+               if (*path == '/')
+                       p = path+1;
+       }
+       return (p);
+}
+
+static int
+readstrfn(void * cookie, char *buf, int len)
+{
+       static char     *current;
+       static int      left;
+       int     copied;
+
+       copied = 0;
+       if (!current) {
+               current = cookie;
+               left = strlen(cookie);
+       }
+       while (*current && left && len) {
+               *buf++ = *current++;
+               left--;
+               len--;
+               copied++;
+       }
+       return copied;
+}
+
+static int
+closestrfn(void * cookie)
+{
+       free(cookie);
+       return 0;
+}
diff --git a/libexec/rtld-elf/libmap.h b/libexec/rtld-elf/libmap.h
new file mode 100644 (file)
index 0000000..10cd3a9
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * $FreeBSD: src/libexec/rtld-elf/libmap.h,v 1.4 2005/02/04 02:46:41 mdodd Exp $
+ */
+
+int    lm_init (char *);
+void   lm_fini (void);
+char * lm_find (const char *, const char *);
index 3650039..f7144bf 100644 (file)
@@ -31,8 +31,7 @@
  * SUCH DAMAGE.
  *
  * @(#)malloc.c        5.11 (Berkeley) 2/23/91
- * $FreeBSD: src/libexec/rtld-elf/malloc.c,v 1.3.2.3 2003/02/20 20:42:46 kan Exp $
- * $DragonFly: src/libexec/rtld-elf/malloc.c,v 1.3 2008/06/05 18:01:49 swildner Exp $
+ * $FreeBSD: src/libexec/rtld-elf/malloc.c, svn 114625 2003/05/04 obrien Exp $
  */
 
 /*
@@ -177,7 +176,7 @@ malloc(nbytes)
                }
                bucket = 0;
                amt = 8;
-               while (pagesz > amt) {
+               while ((unsigned)pagesz > amt) {
                        amt <<= 1;
                        bucket++;
                }
@@ -188,7 +187,7 @@ malloc(nbytes)
         * stored in hash buckets which satisfies request.
         * Account for space used per block for accounting.
         */
-       if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
+       if (nbytes <= (unsigned long)(n = pagesz - sizeof (*op) - RSLOP)) {
 #ifndef RCHECK
                amt = 8;        /* size of first bucket */
                bucket = 0;
@@ -376,7 +375,7 @@ realloc(cp, nbytes)
                        i = NBUCKETS;
        }
        onb = 1 << (i + 3);
-       if (onb < pagesz)
+       if (onb < (u_int)pagesz)
                onb -= sizeof (*op) + RSLOP;
        else
                onb += pagesz - sizeof (*op) - RSLOP;
@@ -389,7 +388,7 @@ realloc(cp, nbytes)
                        else
                                i += pagesz - sizeof (*op) - RSLOP;
                }
-               if (nbytes <= onb && nbytes > i) {
+               if (nbytes <= onb && nbytes > (size_t)i) {
 #ifdef RCHECK
                        op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
                        *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
index a11594e..4ca3ca5 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/map_object.c,v 1.7.2.2 2002/12/28 19:49:41 dillon Exp $
+ * $FreeBSD: src/libexec/rtld-elf/map_object.c,v 1.25 2011/01/25 21:12:31 kib Exp $
  */
 
 #include <sys/param.h>
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "debug.h"
 #include "rtld.h"
 
 static Elf_Ehdr *get_elf_header (int, const char *);
@@ -60,7 +61,6 @@ map_object(int fd, const char *path, const struct stat *sb)
     Elf_Phdr **segs;
     int nsegs;
     Elf_Phdr *phdyn;
-    Elf_Phdr *phphdr;
     Elf_Phdr *phinterp;
     Elf_Phdr *phtls;
     caddr_t mapbase;
@@ -78,25 +78,27 @@ map_object(int fd, const char *path, const struct stat *sb)
     Elf_Addr clear_vaddr;
     caddr_t clear_addr;
     caddr_t clear_page;
-    size_t nclear;
+    Elf_Addr phdr_vaddr;
+    size_t nclear, phsize;
     Elf_Addr bss_vaddr;
     Elf_Addr bss_vlimit;
     caddr_t bss_addr;
 
     hdr = get_elf_header(fd, path);
     if (hdr == NULL)
-       return NULL;
+       return (NULL);
 
     /*
      * Scan the program header entries, and save key information.
      *
-     * We rely on there being exactly two load segments, text and data,
-     * in that order.
+     * We expect that the loadable segments are ordered by load address.
      */
     phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff);
+    phsize  = hdr->e_phnum * sizeof (phdr[0]);
     phlimit = phdr + hdr->e_phnum;
     nsegs = -1;
-    phdyn = phphdr = phinterp = phtls = NULL;
+    phdyn = phinterp = phtls = NULL;
+    phdr_vaddr = 0;
     segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
     while (phdr < phlimit) {
        switch (phdr->p_type) {
@@ -107,7 +109,7 @@ map_object(int fd, const char *path, const struct stat *sb)
 
        case PT_LOAD:
            segs[++nsegs] = phdr;
-           if (segs[nsegs]->p_align < PAGE_SIZE) {
+           if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) {
                _rtld_error("%s: PT_LOAD segment %d not page-aligned",
                    path, nsegs);
                return NULL;
@@ -115,7 +117,8 @@ map_object(int fd, const char *path, const struct stat *sb)
            break;
 
        case PT_PHDR:
-           phphdr = phdr;
+           phdr_vaddr = phdr->p_vaddr;
+           phsize = phdr->p_memsz;
            break;
 
        case PT_DYNAMIC:
@@ -149,8 +152,8 @@ map_object(int fd, const char *path, const struct stat *sb)
     mapsize = base_vlimit - base_vaddr;
     base_addr = hdr->e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL;
 
-    mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
-      convert_flags(segs[0]->p_flags), fd, base_offset);
+    mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
+      MAP_NOCORE, -1, 0);
     if (mapbase == (caddr_t) -1) {
        _rtld_error("%s: mmap of entire address space failed: %s",
          path, strerror(errno));
@@ -163,7 +166,7 @@ map_object(int fd, const char *path, const struct stat *sb)
        return NULL;
     }
 
-    for (i = 0; i <=  nsegs; i++) {
+    for (i = 0; i <= nsegs; i++) {
        /* Overlay the segment onto the proper region. */
        data_offset = trunc_page(segs[i]->p_offset);
        data_vaddr = trunc_page(segs[i]->p_vaddr);
@@ -171,51 +174,60 @@ map_object(int fd, const char *path, const struct stat *sb)
        data_addr = mapbase + (data_vaddr - base_vaddr);
        data_prot = convert_prot(segs[i]->p_flags);
        data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED;
-       /* Do not call mmap on the first segment - this is redundant */
-       if (i && mmap(data_addr, data_vlimit - data_vaddr, data_prot,
+       if (mmap(data_addr, data_vlimit - data_vaddr, data_prot,
          data_flags, fd, data_offset) == (caddr_t) -1) {
            _rtld_error("%s: mmap of data failed: %s", path, strerror(errno));
            return NULL;
        }
 
-       /* Clear any BSS in the last page of the segment. */
-       clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
-       clear_addr = mapbase + (clear_vaddr - base_vaddr);
-       clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr);
-       if ((nclear = data_vlimit - clear_vaddr) > 0) {
-           /* Make sure the end of the segment is writable */
-           if ((data_prot & PROT_WRITE) == 0) {
-               if (mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE) < 0) {
+       /* Do BSS setup */
+       if (segs[i]->p_filesz != segs[i]->p_memsz) {
+
+           /* Clear any BSS in the last page of the segment. */
+           clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
+           clear_addr = mapbase + (clear_vaddr - base_vaddr);
+           clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr);
+
+           if ((nclear = data_vlimit - clear_vaddr) > 0) {
+               /* Make sure the end of the segment is writable */
+               if ((data_prot & PROT_WRITE) == 0) {
+                   if (mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE) < 0) {
                        _rtld_error("%s: mprotect failed: %s", path,
                            strerror(errno));
                        return NULL;
+                   }
                }
-           }
 
-           memset(clear_addr, 0, nclear);
+               memset(clear_addr, 0, nclear);
 
-           /*
-            * reset the data protection back, enable the segment to be
-            * coredumped since we modified it.
-            */
-           if ((data_prot & PROT_WRITE) == 0) {
-               madvise(clear_page, PAGE_SIZE, MADV_CORE);
-               mprotect(clear_page, PAGE_SIZE, data_prot);
+               /*
+                * reset the data protection back, enable the segment to be
+                * coredumped since we modified it.
+                */
+               if ((data_prot & PROT_WRITE) == 0) {
+                   madvise(clear_page, PAGE_SIZE, MADV_CORE);
+                   mprotect(clear_page, PAGE_SIZE, data_prot);
+               }
            }
-       }
 
-       /* Overlay the BSS segment onto the proper region. */
-       bss_vaddr = data_vlimit;
-       bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz);
-       bss_addr = mapbase +  (bss_vaddr - base_vaddr);
-       if (bss_vlimit > bss_vaddr) {   /* There is something to do */
-           if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot,
-               MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) {
-                   _rtld_error("%s: mmap of bss failed: %s", path,
+           /* Overlay the BSS segment onto the proper region. */
+           bss_vaddr = data_vlimit;
+           bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz);
+           bss_addr = mapbase +  (bss_vaddr - base_vaddr);
+           if (bss_vlimit > bss_vaddr) {       /* There is something to do */
+               if (mprotect(bss_addr, bss_vlimit - bss_vaddr, data_prot) == -1) {
+                   _rtld_error("%s: mprotect of bss failed: %s", path,
                        strerror(errno));
-               return NULL;
+                   return NULL;
+               }
            }
        }
+
+       if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff &&
+         (data_vlimit - data_vaddr + data_offset) >=
+         (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) {
+           phdr_vaddr = data_vaddr + hdr->e_phoff - data_offset;
+       }
     }
 
     obj = obj_new();
@@ -232,10 +244,19 @@ map_object(int fd, const char *path, const struct stat *sb)
     obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
     if (hdr->e_entry != 0)
        obj->entry = (caddr_t) (obj->relocbase + hdr->e_entry);
-    if (phphdr != NULL) {
-       obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr);
-       obj->phsize = phphdr->p_memsz;
+    if (phdr_vaddr != 0) {
+       obj->phdr = (const Elf_Phdr *) (obj->relocbase + phdr_vaddr);
+    } else {
+       obj->phdr = malloc(phsize);
+       if (obj->phdr == NULL) {
+           obj_free(obj);
+           _rtld_error("%s: cannot allocate program header", path);
+            return NULL;
+       }
+       memcpy((char *)obj->phdr, (char *)hdr + hdr->e_phoff, phsize);
+       obj->phdr_alloc = true;
     }
+    obj->phsize = phsize;
     if (phinterp != NULL)
        obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
     if (phtls != NULL) {
@@ -258,7 +279,7 @@ get_elf_header (int fd, const char *path)
     } u;
     ssize_t nbytes;
 
-    if ((nbytes = read(fd, u.buf, PAGE_SIZE)) == -1) {
+    if ((nbytes = pread(fd, u.buf, PAGE_SIZE, 0)) == -1) {
        _rtld_error("%s: read error: %s", path, strerror(errno));
        return NULL;
     }
@@ -310,16 +331,18 @@ obj_free(Obj_Entry *obj)
 {
     Objlist_Entry *elm;
 
-    if (obj->tls_done) {
+    if (obj->tls_done)
        free_tls_offset(obj);
-    }
-    free(obj->origin_path);
-    free(obj->path);
     while (obj->needed != NULL) {
        Needed_Entry *needed = obj->needed;
        obj->needed = needed->next;
        free(needed);
     }
+    while (!STAILQ_EMPTY(&obj->names)) {
+       Name_Entry *entry = STAILQ_FIRST(&obj->names);
+       STAILQ_REMOVE_HEAD(&obj->names, link);
+       free(entry);
+    }
     while (!STAILQ_EMPTY(&obj->dldags)) {
        elm = STAILQ_FIRST(&obj->dldags);
        STAILQ_REMOVE_HEAD(&obj->dldags, link);
@@ -330,6 +353,18 @@ obj_free(Obj_Entry *obj)
        STAILQ_REMOVE_HEAD(&obj->dagmembers, link);
        free(elm);
     }
+    if (obj->vertab)
+       free(obj->vertab);
+    if (obj->origin_path)
+       free(obj->origin_path);
+    if (obj->z_origin)
+       free(obj->rpath);
+    if (obj->priv)
+       free(obj->priv);
+    if (obj->path)
+       free(obj->path);
+    if (obj->phdr_alloc)
+       free((void *)obj->phdr);
     free(obj);
 }
 
@@ -341,6 +376,7 @@ obj_new(void)
     obj = CNEW(Obj_Entry);
     STAILQ_INIT(&obj->dldags);
     STAILQ_INIT(&obj->dagmembers);
+    STAILQ_INIT(&obj->names);
     return obj;
 }
 
index 0eadb30..a4eed74 100644 (file)
@@ -1,5 +1,3 @@
-.\" $FreeBSD: src/libexec/rtld-elf/rtld.1,v 1.18.2.7 2002/01/10 17:51:28 ru Exp $
-.\"
 .\" Copyright (c) 1995 Paul Kranenburg
 .\" All rights reserved.
 .\"
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
+.\" $FreeBSD: src/libexec/rtld-elf/rtld.1 216695 2010-12-25 08:51:20Z kib $
+.\"
 .Dd February 21, 2011
 .Dt RTLD 1
 .Os
 .Sh NAME
-.Nm ld-elf.so.1 ,
 .Nm ld-elf.so.2 ,
+.Nm ld-elf.so.1 ,
 .Nm rtld ,
 .Nm _rtld_functrace
 .Nd run-time link-editor
@@ -41,8 +41,9 @@
 .Ft int
 .Fn _rtld_functrace "const char *callerso" "const char *calleeso" "const char *calleefun" "void *stack"
 .Sh DESCRIPTION
+The
 .Nm
-is a self-contained shared object providing run-time
+utility is a self-contained shared object providing run-time
 support for loading and link-editing shared objects into a process'
 address space.
 It is also commonly known as the dynamic linker.
@@ -61,8 +62,28 @@ to be called on a per-object basis, giving a shared object an opportunity
 to perform any extra set-up before execution of the program proper begins.
 This is useful for C++ libraries that contain static constructors.
 .Pp
+When resolving dependencies for the loaded objects,
 .Nm
-itself is loaded by the kernel together with any dynamically-linked
+may be allowed to translate dynamic token strings in rpath and soname
+by setting
+.Fl "z origin"
+option of the static linker
+.Xr ld 1 .
+The following strings are recognized now:
+.Bl -tag -width ".Pa $PLATFORM"
+.It Pa $ORIGIN
+Translated to the full path of the loaded object.
+.It Pa $OSNAME
+Translated to the name of the operating system implementation.
+.It Pa $OSREL
+Translated to the release level of the operating system.
+.It Pa $PLATFORM
+Translated to the machine hardware platform.
+.El
+.Pp
+The
+.Nm
+utility itself is loaded by the kernel together with any dynamically-linked
 program that is to be executed.
 The kernel transfers control to the
 dynamic linker.
@@ -70,7 +91,7 @@ After the dynamic linker has finished loading,
 relocating, and initializing the program and its required shared
 objects, it transfers control to the entry point of the program.
 .Pp
-To locate the required shared objects in the filesystem,
+To locate the required shared objects in the file system,
 .Nm
 may use a
 .Dq hints
@@ -78,14 +99,49 @@ file prepared by the
 .Xr ldconfig 8
 utility.
 .Pp
+The
 .Nm
+utility
 recognizes a number of environment variables that can be used to modify
 its behaviour as follows:
-.Bl -tag -width ".Ev LD_LIBRARY_PATH"
+.Bl -tag -width ".Ev LD_LIBMAP_DISABLE"
+.It Ev LD_DUMP_REL_POST
+If set,
+.Nm
+will print a table containing all relocations after symbol
+binding and relocation.
+.It Ev LD_DUMP_REL_PRE
+If set,
+.Nm
+will print a table containing all relocations before symbol
+binding and relocation.
+.It Ev LD_LIBMAP
+A library replacement list in the same format as
+.Xr libmap.conf 5 .
+For convenience, the characters
+.Ql =
+and
+.Ql \&,
+can be used instead of a space and a newline.
+This variable is parsed after
+.Xr libmap.conf 5 ,
+and will override its entries.
+This variable is unset for set-user-ID and set-group-ID programs.
+.It Ev LD_LIBMAP_DISABLE
+If set, disables the use of
+.Xr libmap.conf 5
+and
+.Ev LD_LIBMAP .
+This variable is unset for set-user-ID and set-group-ID programs.
+.It Ev LD_ELF_HINTS_PATH
+This variable will override the default location of
+.Dq hints
+file.
+This variable is unset for set-user-ID and set-group-ID programs.
 .It Ev LD_LIBRARY_PATH
 A colon separated list of directories, overriding the default search path
 for shared libraries.
-This is ignored for set-user-ID and set-group-ID programs.
+This variable is unset for set-user-ID and set-group-ID programs.
 .It Ev LD_PRELOAD
 A list of shared libraries, separated by colons and/or white space,
 to be linked in before any
@@ -95,7 +151,7 @@ the directories specified by
 .Ev LD_LIBRARY_PATH
 will be searched first
 followed by the set of built-in standard directories.
-This is ignored for set-user-ID and set-group-ID programs.
+This variable is unset for set-user-ID and set-group-ID programs.
 .It Ev LD_BIND_NOW
 When set to a nonempty string, causes
 .Nm
@@ -111,6 +167,11 @@ When set to a nonempty string, causes
 .Nm
 to exit after loading the shared objects and printing a summary which includes
 the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_ALL
+When set to a nonempty string, causes
+.Nm
+to expand the summary to indicate which objects caused each object to
+be loaded.
 .It Ev LD_TRACE_LOADED_OBJECTS_FMT1
 .It Ev LD_TRACE_LOADED_OBJECTS_FMT2
 When set, these variables are interpreted as format strings a la
@@ -121,6 +182,12 @@ to customize the trace output and are used by
 option and allows
 .Xr ldd 1
 to be operated as a filter more conveniently.
+If the dependency name starts with string
+.Pa lib ,
+.Ev LD_TRACE_LOADED_OBJECTS_FMT1
+is used, otherwise
+.Ev LD_TRACE_LOADED_OBJECTS_FMT2
+is used.
 The following conversions can be used:
 .Bl -tag -width 4n
 .It Li %a
@@ -129,11 +196,12 @@ The main program's name
 .Dq __progname ) .
 .It Li \&%A
 The value of the environment variable
-.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME .
+Typically used to print both the names of programs and shared libraries
+being inspected using
+.Xr ldd 1 .
 .It Li %o
 The library name.
-.It Li %m
-The library's major version number.
 .It Li %p
 The full pathname as determined by
 .Nm rtld Ns 's
@@ -147,6 +215,11 @@ Additionally,
 and
 .Ql \et
 are recognized and have their usual meaning.
+.It Ev LD_UTRACE
+If set,
+.Nm
+will log events such as the loading and unloading of shared objects via
+.Xr utrace 2 .
 .El
 .Pp
 If a shared object preloaded by the
@@ -178,8 +251,11 @@ and to give threading libraries a chance to complete initialization of the
 TCB prior to the calling of the _init() functions for the dynamically loaded
 libraries.
 .Sh FILES
-.Bl -tag -width indent
+.Bl -tag -width ".Pa /var/run/ld-elf.so.hints" -compact
 .It Pa /var/run/ld-elf.so.hints
+Hints file.
+.It Pa /etc/libmap.conf
+The libmap configuration file.
 .El
 .Sh EXAMPLES
 To set up an
@@ -217,4 +293,5 @@ will activate it.
 .Xr ld 1 ,
 .Xr ldd 1 ,
 .Xr elf 5 ,
+.Xr libmap.conf 5 ,
 .Xr ldconfig 8
index 791a90b..65aeee0 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
  * Copyright 2003 Alexander Kabaev <kan@FreeBSD.ORG>.
+ * Copyright 2009, 2010, 2011 Konstantin Belousov <kib@FreeBSD.ORG>.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,7 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.43.2.15 2003/02/20 20:42:46 kan Exp $
+ * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.173 2011/02/09 09:20:27 kib Exp $
  */
 
 /*
 #endif
 
 #include <sys/param.h>
+#include <sys/mount.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+#include <sys/ktrace.h>
 #include <sys/resident.h>
 #include <sys/tls.h>
 
@@ -56,6 +61,7 @@
 
 #include "debug.h"
 #include "rtld.h"
+#include "libmap.h"
 
 #define PATH_RTLD      "/usr/libexec/ld-elf.so.2"
 #define LD_ARY_CACHE   16
@@ -77,76 +83,91 @@ typedef struct Struct_DoneList {
 /*
  * Function declarations.
  */
-static void die(void);
-static void digest_dynamic(Obj_Entry *, int);
 static const char *_getenv_ld(const char *id);
+static void die(void) __dead2;
+static void digest_dynamic(Obj_Entry *, int);
 static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
 static Obj_Entry *dlcheck(void *);
+static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int);
 static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
 static bool donelist_check(DoneList *, const Obj_Entry *);
 static void errmsg_restore(char *);
 static char *errmsg_save(void);
 static void *fill_search_info(const char *, size_t, void *);
 static char *find_library(const char *, const Obj_Entry *);
-static Obj_Entry *find_object(const char *);
-static Obj_Entry *find_object2(const char *, int *, struct stat *);
 static const char *gethints(void);
 static void init_dag(Obj_Entry *);
-static void init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *);
+static void init_dag1(Obj_Entry *, Obj_Entry *, DoneList *);
 static void init_rtld(caddr_t);
-static void initlist_add_neededs(Needed_Entry *needed, Objlist *list);
-static void initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail,
-  Objlist *list);
+static void initlist_add_neededs(Needed_Entry *, Objlist *);
+static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
 static bool is_exported(const Elf_Sym *);
 static void linkmap_add(Obj_Entry *);
 static void linkmap_delete(Obj_Entry *);
-static int load_needed_objects(Obj_Entry *);
+static int load_needed_objects(Obj_Entry *, int);
 static int load_preload_objects(void);
-static Obj_Entry *load_object(char *);
-static void lock_check(void);
+static Obj_Entry *load_object(const char *, const Obj_Entry *, int);
 static Obj_Entry *obj_from_addr(const void *);
-static void objlist_call_fini(Objlist *);
-static void objlist_call_init(Objlist *);
+static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *);
+static void objlist_call_init(Objlist *, RtldLockState *);
 static void objlist_clear(Objlist *);
 static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *);
 static void objlist_init(Objlist *);
 static void objlist_push_head(Objlist *, Obj_Entry *);
 static void objlist_push_tail(Objlist *, Obj_Entry *);
 static void objlist_remove(Objlist *, Obj_Entry *);
-static void objlist_remove_unref(Objlist *);
 static void *path_enumerate(const char *, path_enum_proc, void *);
 static int relocate_objects(Obj_Entry *, bool, Obj_Entry *);
 static int rtld_dirname(const char *, char *);
+static int rtld_dirname_abs(const char *, char *);
 static void rtld_exit(void);
 static char *search_library_path(const char *, const char *);
-static const void **get_program_var_addr(const char *name);
+static const void **get_program_var_addr(const char *);
 static void set_program_var(const char *, const void *);
-static const Elf_Sym *symlook_default(const char *, unsigned long hash,
-  const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt);
-static const Elf_Sym *symlook_list(const char *, unsigned long,
-  const Objlist *, const Obj_Entry **, bool in_plt, DoneList *);
+static const Elf_Sym *symlook_default(const char *, unsigned long,
+  const Obj_Entry *, const Obj_Entry **, const Ver_Entry *, int);
+static const Elf_Sym *symlook_list(const char *, unsigned long, const Objlist *,
+  const Obj_Entry **, const Ver_Entry *, int, DoneList *);
 static const Elf_Sym *symlook_needed(const char *, unsigned long,
-  const Needed_Entry *, const Obj_Entry **, bool in_plt, DoneList *);
-static void trace_loaded_objects(Obj_Entry *obj);
+  const Needed_Entry *, const Obj_Entry **, const Ver_Entry *,
+  int, DoneList *);
+static void trace_loaded_objects(Obj_Entry *);
 static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *);
 static void unref_dag(Obj_Entry *);
-
-void r_debug_state(struct r_debug*, struct link_map*);
+static void ref_dag(Obj_Entry *);
+static int origin_subst_one(char **, const char *, const char *,
+  const char *, char *);
+static char *origin_subst(const char *, const char *);
+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 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);
+
+void r_debug_state(struct r_debug *, struct link_map *);
 
 /*
  * Data declarations.
  */
 static char *error_message;    /* Message for dlerror(), or NULL */
 struct r_debug r_debug;                /* for GDB; */
+static bool libmap_disable;    /* Disable libmap */
+static 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 */
 static const char *ld_bind_now;        /* Environment variable for immediate binding */
 static const char *ld_debug;   /* Environment variable for debugging */
 static const char *ld_library_path; /* Environment variable for search path */
 static char *ld_preload;       /* Environment variable for libraries to
                                   load first */
+static const char *ld_elf_hints_path; /* Environment variable for alternative hints path */
 static const char *ld_tracing; /* Called from ldd(1) to print libs */
                                /* Optional function call tracing hook */
+static const char *ld_utrace;  /* Use utrace() to log events. */
 static int (*rtld_functrace)(const char *caller_obj,
                             const char *callee_obj,
                             const char *callee_func,
@@ -158,6 +179,8 @@ static Obj_Entry **preload_tail;
 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 objects in obj_list */
+
 static int     ld_resident;    /* Non-zero if resident */
 static const char *ld_ary[LD_ARY_CACHE];
 static int     ld_index;
@@ -170,14 +193,15 @@ static Objlist list_main =        /* Objects loaded at program startup */
 static Objlist list_fini =     /* Objects needing fini() calls */
   STAILQ_HEAD_INITIALIZER(list_fini);
 
-static LockInfo lockinfo;
-
 static 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
+#ifndef RTLD_IS_DYNAMIC
+#define        RTLD_IS_DYNAMIC()       (&_DYNAMIC != NULL)
+#endif
 
 /*
  * These are the functions the dynamic linker exports to application
@@ -189,9 +213,12 @@ static func_ptr_type exports[] = {
     (func_ptr_type) &dlclose,
     (func_ptr_type) &dlerror,
     (func_ptr_type) &dlopen,
+    (func_ptr_type) &dlfunc,
     (func_ptr_type) &dlsym,
+    (func_ptr_type) &dlvsym,
     (func_ptr_type) &dladdr,
     (func_ptr_type) &dlinfo,
+    (func_ptr_type) &dl_iterate_phdr,
 #ifdef __i386__
     (func_ptr_type) &___tls_get_addr,
 #endif
@@ -200,6 +227,8 @@ static func_ptr_type exports[] = {
     (func_ptr_type) &_rtld_allocate_tls,
     (func_ptr_type) &_rtld_free_tls,
     (func_ptr_type) &_rtld_call_init,
+    (func_ptr_type) &_rtld_thread_init,
+    (func_ptr_type) &_rtld_addr_phdr,
     NULL
 };
 
@@ -230,34 +259,51 @@ int tls_max_index = 1;            /* Largest module index allocated */
     (dlp)->num_alloc = obj_count,                              \
     (dlp)->num_used = 0)
 
-static __inline void
-rlock_acquire(void)
-{
-    lockinfo.rlock_acquire(lockinfo.thelock);
-    atomic_incr_int(&lockinfo.rcount);
-    lock_check();
-}
-
-static __inline void
-wlock_acquire(void)
-{
-    lockinfo.wlock_acquire(lockinfo.thelock);
-    atomic_incr_int(&lockinfo.wcount);
-    lock_check();
-}
+#define        UTRACE_DLOPEN_START             1
+#define        UTRACE_DLOPEN_STOP              2
+#define        UTRACE_DLCLOSE_START            3
+#define        UTRACE_DLCLOSE_STOP             4
+#define        UTRACE_LOAD_OBJECT              5
+#define        UTRACE_UNLOAD_OBJECT            6
+#define        UTRACE_ADD_RUNDEP               7
+#define        UTRACE_PRELOAD_FINISHED         8
+#define        UTRACE_INIT_CALL                9
+#define        UTRACE_FINI_CALL                10
+
+struct utrace_rtld {
+       char sig[4];                    /* 'RTLD' */
+       int event;
+       void *handle;
+       void *mapbase;                  /* Used for 'parent' and 'init/fini' */
+       size_t mapsize;
+       int refcnt;                     /* Used for 'mode' */
+       char name[MAXPATHLEN];
+};
 
-static __inline void
-rlock_release(void)
-{
-    atomic_decr_int(&lockinfo.rcount);
-    lockinfo.rlock_release(lockinfo.thelock);
-}
+#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 __inline void
-wlock_release(void)
-{
-    atomic_decr_int(&lockinfo.wcount);
-    lockinfo.wlock_release(lockinfo.thelock);
+static void
+ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
+    int refcnt, const char *name)
+{
+       struct utrace_rtld ut;
+
+       ut.sig[0] = 'R';
+       ut.sig[1] = 'T';
+       ut.sig[2] = 'L';
+       ut.sig[3] = 'D';
+       ut.event = event;
+       ut.handle = handle;
+       ut.mapbase = mapbase;
+       ut.mapsize = mapsize;
+       ut.refcnt = refcnt;
+       bzero(ut.name, sizeof(ut.name));
+       if (name)
+               strlcpy(ut.name, name, sizeof(ut.name));
+       utrace(&ut, sizeof(ut));
 }
 
 /*
@@ -290,6 +336,13 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     Objlist_Entry *entry;
     Obj_Entry *obj;
 
+    /* marino: DO NOT MOVE THESE VARIABLES TO _rtld
+             Obj_Entry **preload_tail;
+             Objlist initlist;
+       from global to here.  It will break the DRAWF2 unwind scheme.
+       The system compilers were unaffected, but not gcc 4.6
+    */
+
     /*
      * On entry, the dynamic linker itself has not been relocated yet.
      * Be very careful not to reference any global data until after
@@ -335,15 +388,44 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     argv0 = argv[0] != NULL ? argv[0] : "(null)";
     environ = env;
 
-    trust = (geteuid() == getuid()) && (getegid() == getgid());
+    trust = !issetugid();
 
     ld_bind_now = _getenv_ld("LD_BIND_NOW");
-    if (trust) {
-       ld_debug = _getenv_ld("LD_DEBUG");
-       ld_library_path = _getenv_ld("LD_LIBRARY_PATH");
-       ld_preload = (char *)_getenv_ld("LD_PRELOAD");
+    /*
+     * 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) {
+       if (   unsetenv("LD_DEBUG")
+           || unsetenv("LD_PRELOAD")
+           || unsetenv("LD_LIBRARY_PATH")
+           || unsetenv("LD_ELF_HINTS_PATH")
+           || unsetenv("LD_LIBMAP")
+           || unsetenv("LD_LIBMAP_DISABLE")
+       ) {
+           _rtld_error("environment corrupt; aborting");
+           die();
+       }
     }
+    ld_debug = _getenv_ld("LD_DEBUG");
+    ld_library_path = _getenv_ld("LD_LIBRARY_PATH");
+    ld_preload = (char *)_getenv_ld("LD_PRELOAD");
+    ld_elf_hints_path = _getenv_ld("LD_ELF_HINTS_PATH");
+    libmap_override = (char *)_getenv_ld("LD_LIBMAP");
+    libmap_disable = _getenv_ld("LD_LIBMAP_DISABLE") != NULL;
+    dangerous_ld_env = (ld_library_path != NULL)
+                       || (ld_preload != NULL)
+                       || (ld_elf_hints_path != NULL)
+                       || (libmap_override != NULL)
+                       || libmap_disable
+                       ;
     ld_tracing = _getenv_ld("LD_TRACE_LOADED_OBJECTS");
+    ld_utrace = _getenv_ld("LD_UTRACE");
+
+    if ((ld_elf_hints_path == NULL) || strlen(ld_elf_hints_path) == 0)
+       ld_elf_hints_path = _PATH_ELF_HINTS;
 
     if (ld_debug != NULL && *ld_debug != '\0')
        debug = 1;
@@ -352,6 +434,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     dbg("RTLD dynamic = %p", obj_rtld.dynamic);
     dbg("RTLD pltgot  = %p", obj_rtld.pltgot);
 
+    dbg("initializing thread locks");
+    lockdflt_init();
+
     /*
      * If we are resident we can skip work that we have already done.
      * Note that the stack is reset and there is no Elf_Auxinfo
@@ -390,7 +475,40 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
            die();
     }
 
-    obj_main->path = xstrdup(argv0);
+    char buf[MAXPATHLEN];
+    if (aux_info[AT_EXECPATH] != 0) {
+       char *kexecpath;
+
+       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 {
+       char resolved[MAXPATHLEN];
+       dbg("No AT_EXECPATH");
+       if (argv0[0] == '/') {
+               if (realpath(argv0, resolved) != NULL)
+                       obj_main->path = xstrdup(resolved);
+               else
+                       obj_main->path = xstrdup(argv0);
+       } else {
+               if (getcwd(buf, sizeof(buf)) != NULL
+                   && strlcat(buf, "/", sizeof(buf)) < sizeof(buf)
+                   && strlcat(buf, argv0, sizeof (buf)) < sizeof(buf)
+                   && access(buf, R_OK) == 0
+                   && realpath(buf, resolved) != NULL)
+                       obj_main->path = xstrdup(resolved);
+               else
+                       obj_main->path = xstrdup(argv0);
+       }
+    }
+    dbg("obj_main path %s", obj_main->path);
     obj_main->mainprog = true;
 
     /*
@@ -415,13 +533,17 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     *obj_tail = obj_main;
     obj_tail = &obj_main->next;
     obj_count++;
-    obj_main->refcount++;
+    obj_loads++;
     /* Make sure we don't call the main program's init and fini functions. */
-    obj_main->init = obj_main->fini = NULL;
+    obj_main->init = obj_main->fini = (Elf_Addr)NULL;
 
     /* 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_ABS;
+    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);
 
     dbg("loading LD_PRELOAD libraries");
     if (load_preload_objects() == -1)
@@ -429,12 +551,18 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     preload_tail = obj_tail;
 
     dbg("loading needed objects");
-    if (load_needed_objects(obj_main) == -1)
+    if (load_needed_objects(obj_main, 0) == -1)
        die();
 
     /* Make a list of all objects loaded at startup. */
-    for (obj = obj_list;  obj != NULL;  obj = obj->next)
+    for (obj = obj_list;  obj != NULL;  obj = obj->next) {
        objlist_push_tail(&list_main, obj);
+       obj->refcount++;
+    }
+
+    dbg("checking for required versions");
+    if (rtld_verify_versions(&list_main) == -1 && !ld_tracing)
+       die();
 
 resident_skip1:
 
@@ -446,7 +574,7 @@ resident_skip1:
     if (ld_resident)           /* XXX clean this up! */
        goto resident_skip2;
 
-    if (getenv("LD_DUMP_REL_PRE") != NULL) {
+    if (_getenv_ld("LD_DUMP_REL_PRE") != NULL) {
        dump_relocations(obj_main);
        exit (0);
     }
@@ -487,7 +615,7 @@ resident_skip2:
        exit(0);
     }
 
-    if (getenv("LD_DUMP_REL_POST") != NULL) {
+    if (_getenv_ld("LD_DUMP_REL_POST") != NULL) {
        dump_relocations(obj_main);
        exit (0);
     }
@@ -507,10 +635,6 @@ resident_skip2:
        exit(0);
     }
 
-    dbg("initializing thread locks");
-    lockdflt_init(&lockinfo);
-    lockinfo.thelock = lockinfo.lock_create(lockinfo.context);
-
     /* Make a list of init functions to call. */
     objlist_init(&initlist);
     initlist_add_objects(obj_list, preload_tail, &initlist);
@@ -537,10 +661,12 @@ resident_skip2:
 void
 _rtld_call_init(void)
 {
-    objlist_call_init(&initlist);
-    wlock_acquire();
+    RtldLockState lockstate;
+
+    wlock_acquire(rtld_bind_lock, &lockstate);
+    objlist_call_init(&initlist, &lockstate);
     objlist_clear(&initlist);
-    wlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
 }
 
 Elf_Addr
@@ -551,9 +677,12 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff, void *stack)
     const Obj_Entry *defobj;
     Elf_Addr *where;
     Elf_Addr target;
+    RtldLockState lockstate;
     int do_reloc = 1;
 
-    rlock_acquire();
+    rlock_acquire(rtld_bind_lock, &lockstate);
+    if (sigsetjmp(lockstate.env, 0) != 0)
+           lock_upgrade(rtld_bind_lock, &lockstate);
     if (obj->pltrel)
        rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
     else
@@ -569,7 +698,6 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff, void *stack)
     dbg("\"%s\" in \"%s\" ==> %p in \"%s\"",
       defobj->strtab + def->st_name, basename(obj->path),
       (void *)target, basename(defobj->path));
-    rlock_release();
 
     /*
      * If we have a function call tracing hook, and the
@@ -589,7 +717,8 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff, void *stack)
     }
 
     if (do_reloc)
-       reloc_jmpslot(where, target);
+       target = reloc_jmpslot(where, target, defobj, obj, rel);
+    lock_release(rtld_bind_lock, &lockstate);
     return target;
 }
 
@@ -641,6 +770,83 @@ basename(const char *name)
     return p != NULL ? p + 1 : name;
 }
 
+static struct utsname uts;
+
+static int
+origin_subst_one(char **res, const char *real, const char *kw, const char *subst,
+    char *may_free)
+{
+    const char *p, *p1;
+    char *res1;
+    int subst_len;
+    int kw_len;
+
+    res1 = *res = NULL;
+    p = real;
+    subst_len = kw_len = 0;
+    for (;;) {
+        p1 = strstr(p, kw);
+        if (p1 != NULL) {
+            if (subst_len == 0) {
+                subst_len = strlen(subst);
+                kw_len = strlen(kw);
+            }
+            if (*res == NULL) {
+                *res = xmalloc(PATH_MAX);
+                res1 = *res;
+            }
+            if ((res1 - *res) + subst_len + (p1 - p) >= PATH_MAX) {
+                _rtld_error("Substitution of %s in %s cannot be performed",
+                    kw, real);
+                if (may_free != NULL)
+                    free(may_free);
+                free(res);
+                return (false);
+            }
+            memcpy(res1, p, p1 - p);
+            res1 += p1 - p;
+            memcpy(res1, subst, subst_len);
+            res1 += subst_len;
+            p = p1 + kw_len;
+        } else {
+           if (*res == NULL) {
+               if (may_free != NULL)
+                   *res = may_free;
+               else
+                   *res = xstrdup(real);
+               return (true);
+           }
+           *res1 = '\0';
+           if (may_free != NULL)
+               free(may_free);
+           if (strlcat(res1, p, PATH_MAX - (res1 - *res)) >= PATH_MAX) {
+               free(res);
+               return (false);
+           }
+           return (true);
+        }
+    }
+}
+
+static char *
+origin_subst(const char *real, const char *origin_path)
+{
+    char *res1, *res2, *res3, *res4;
+
+    if (uts.sysname[0] == '\0') {
+       if (uname(&uts) != 0) {
+           _rtld_error("utsname failed: %d", errno);
+           return (NULL);
+       }
+    }
+    if (!origin_subst_one(&res1, real, "$ORIGIN", origin_path, NULL) ||
+       !origin_subst_one(&res2, res1, "$OSNAME", uts.sysname, res1) ||
+       !origin_subst_one(&res3, res2, "$OSREL", uts.release, res2) ||
+       !origin_subst_one(&res4, res3, "$PLATFORM", uts.machine, res3))
+           return (NULL);
+    return (res4);
+}
+
 static void
 die(void)
 {
@@ -661,8 +867,10 @@ digest_dynamic(Obj_Entry *obj, int early)
     const Elf_Dyn *dynp;
     Needed_Entry **needed_tail = &obj->needed;
     const Elf_Dyn *dyn_rpath = NULL;
+    const Elf_Dyn *dyn_soname = NULL;
     int plttype = DT_REL;
 
+    obj->bind_now = false;
     for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
        switch (dynp->d_tag) {
 
@@ -721,6 +929,29 @@ digest_dynamic(Obj_Entry *obj, int early)
            obj->strsize = dynp->d_un.d_val;
            break;
 
+       case DT_VERNEED:
+           obj->verneed = (const Elf_Verneed *) (obj->relocbase +
+               dynp->d_un.d_val);
+           break;
+
+       case DT_VERNEEDNUM:
+           obj->verneednum = dynp->d_un.d_val;
+           break;
+
+       case DT_VERDEF:
+           obj->verdef = (const Elf_Verdef *) (obj->relocbase +
+               dynp->d_un.d_val);
+           break;
+
+       case DT_VERDEFNUM:
+           obj->verdefnum = dynp->d_un.d_val;
+           break;
+
+       case DT_VERSYM:
+           obj->versyms = (const Elf_Versym *)(obj->relocbase +
+               dynp->d_un.d_val);
+           break;
+
        case DT_HASH:
            {
                const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
@@ -766,15 +997,15 @@ digest_dynamic(Obj_Entry *obj, int early)
            break;
 
        case DT_SONAME:
-           /* Not used by the dynamic linker. */
+           dyn_soname = dynp;
            break;
 
        case DT_INIT:
-           obj->init = (InitFunc) (obj->relocbase + dynp->d_un.d_ptr);
+           obj->init = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
            break;
 
        case DT_FINI:
-           obj->fini = (InitFunc) (obj->relocbase + dynp->d_un.d_ptr);
+           obj->fini = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
            break;
 
        case DT_DEBUG:
@@ -785,11 +1016,8 @@ digest_dynamic(Obj_Entry *obj, int early)
            break;
 
        case DT_FLAGS:
-               if (dynp->d_un.d_val & DF_ORIGIN) {
-                   obj->origin_path = xmalloc(PATH_MAX);
-                   if (rtld_dirname(obj->path, obj->origin_path) == -1)
-                       die();
-               }
+               if ((dynp->d_un.d_val & DF_ORIGIN) && trust)
+                   obj->z_origin = true;
                if (dynp->d_un.d_val & DF_SYMBOLIC)
                    obj->symbolic = true;
                if (dynp->d_un.d_val & DF_TEXTREL)
@@ -800,9 +1028,24 @@ digest_dynamic(Obj_Entry *obj, int early)
                    ;
            break;
 
+       case DT_FLAGS_1:
+               if (dynp->d_un.d_val & DF_1_NOOPEN)
+                   obj->z_noopen = true;
+               if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
+                   obj->z_origin = true;
+               if (dynp->d_un.d_val & DF_1_GLOBAL)
+                       /* XXX */;
+               if (dynp->d_un.d_val & DF_1_BIND_NOW)
+                   obj->bind_now = true;
+               if (dynp->d_un.d_val & DF_1_NODELETE)
+                   obj->z_nodelete = true;
+           break;
+
        default:
-           if (!early)
-               dbg("Ignoring d_tag %d = %#x", dynp->d_tag, dynp->d_tag);
+           if (!early) {
+               dbg("Ignoring d_tag %ld = %#lx", (long)dynp->d_tag,
+                   (long)dynp->d_tag);
+           }
            break;
        }
     }
@@ -816,8 +1059,20 @@ digest_dynamic(Obj_Entry *obj, int early)
        obj->pltrelsize = 0;
     }
 
-    if (dyn_rpath != NULL)
-       obj->rpath = obj->strtab + dyn_rpath->d_un.d_val;
+    if (obj->z_origin && obj->origin_path == NULL) {
+       obj->origin_path = xmalloc(PATH_MAX);
+       if (rtld_dirname_abs(obj->path, obj->origin_path) == -1)
+           die();
+    }
+
+    if (dyn_rpath != NULL) {
+       obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
+       if (obj->z_origin)
+           obj->rpath = origin_subst(obj->rpath, obj->origin_path);
+    }
+
+    if (dyn_soname != NULL)
+       object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
 }
 
 /*
@@ -836,26 +1091,26 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
 
     obj = obj_new();
     for (ph = phdr;  ph < phlimit;  ph++) {
-       switch (ph->p_type) {
+       if (ph->p_type != PT_PHDR)
+           continue;
 
-       case PT_PHDR:
-           if ((const Elf_Phdr *)ph->p_vaddr != phdr) {
-               _rtld_error("%s: invalid PT_PHDR", path);
-               return NULL;
-           }
-           obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
-           obj->phsize = ph->p_memsz;
-           break;
+       obj->phdr = phdr;
+       obj->phsize = ph->p_memsz;
+       obj->relocbase = (caddr_t)phdr - ph->p_vaddr;
+       break;
+    }
+
+    for (ph = phdr;  ph < phlimit;  ph++) {
+       switch (ph->p_type) {
 
        case PT_INTERP:
-           obj->interp = (const char *) ph->p_vaddr;
+           obj->interp = (const char *)(ph->p_vaddr + obj->relocbase);
            break;
 
        case PT_LOAD:
            if (nsegs == 0) {   /* First load segment */
                obj->vaddrbase = trunc_page(ph->p_vaddr);
-               obj->mapbase = (caddr_t) obj->vaddrbase;
-               obj->relocbase = obj->mapbase - obj->vaddrbase;
+               obj->mapbase = obj->vaddrbase + obj->relocbase;
                obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) -
                  obj->vaddrbase;
            } else {            /* Last load segment */
@@ -866,7 +1121,7 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
            break;
 
        case PT_DYNAMIC:
-           obj->dynamic = (const Elf_Dyn *) ph->p_vaddr;
+           obj->dynamic = (const Elf_Dyn *)(ph->p_vaddr + obj->relocbase);
            break;
 
        case PT_TLS:
@@ -874,7 +1129,7 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
            obj->tlssize = ph->p_memsz;
            obj->tlsalign = ph->p_align;
            obj->tlsinitsize = ph->p_filesz;
-           obj->tlsinit = (void*) ph->p_vaddr;
+           obj->tlsinit = (void*)(ph->p_vaddr + obj->relocbase);
            break;
        }
     }
@@ -961,19 +1216,27 @@ elf_hash(const char *name)
  *   /usr/lib
  */
 static char *
-find_library(const char *name, const Obj_Entry *refobj)
+find_library(const char *xname, const Obj_Entry *refobj)
 {
     char *pathname;
+    char *name;
 
-    if (strchr(name, '/') != NULL) {   /* Hard coded pathname */
-       if (name[0] != '/' && !trust) {
+    if (strchr(xname, '/') != NULL) {  /* Hard coded pathname */
+       if (xname[0] != '/' && !trust) {
            _rtld_error("Absolute pathname required for shared object \"%s\"",
-             name);
+             xname);
            return NULL;
        }
-       return xstrdup(name);
+       if (refobj != NULL && refobj->z_origin)
+           return origin_subst(xname, refobj->origin_path);
+       else
+           return xstrdup(xname);
     }
 
+    if (libmap_disable || (refobj == NULL) ||
+       (name = lm_find(refobj->path, xname)) == NULL)
+       name = (char *)xname;
+
     dbg(" Searching for \"%s\"", name);
 
     if ((pathname = search_library_path(name, ld_library_path)) != NULL ||
@@ -1000,11 +1263,12 @@ find_library(const char *name, const Obj_Entry *refobj)
  */
 const Elf_Sym *
 find_symdef(unsigned long symnum, const Obj_Entry *refobj,
-    const Obj_Entry **defobj_out, bool in_plt, SymCache *cache)
+    const Obj_Entry **defobj_out, int flags, SymCache *cache)
 {
     const Elf_Sym *ref;
     const Elf_Sym *def;
     const Obj_Entry *defobj;
+    const Ver_Entry *ventry;
     const char *name;
     unsigned long hash;
 
@@ -1038,8 +1302,9 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj,
            _rtld_error("%s: Bogus symbol table entry %lu", refobj->path,
                symnum);
        }
+       ventry = fetch_ventry(refobj, symnum);
        hash = elf_hash(name);
-       def = symlook_default(name, hash, refobj, &defobj, in_plt);
+       def = symlook_default(name, hash, refobj, &defobj, ventry, flags);
     } else {
        def = ref;
        defobj = refobj;
@@ -1061,8 +1326,10 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj,
            cache[symnum].sym = def;
            cache[symnum].obj = defobj;
        }
-    } else
-       _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
+    } else {
+       if (refobj != &obj_rtld)
+           _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
+    }
     return def;
 }
 
@@ -1084,7 +1351,7 @@ gethints(void)
        /* Keep from trying again in case the hints file is bad. */
        hints = "";
 
-       if ((fd = open(_PATH_ELF_HINTS, O_RDONLY)) == -1)
+       if ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1)
            return NULL;
        if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
          hdr.magic != ELFHINTS_MAGIC ||
@@ -1094,7 +1361,7 @@ gethints(void)
        }
        p = xmalloc(hdr.dirlistlen + 1);
        if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 ||
-         read(fd, p, hdr.dirlistlen + 1) != hdr.dirlistlen + 1) {
+         read(fd, p, hdr.dirlistlen + 1) != (ssize_t)hdr.dirlistlen + 1) {
            free(p);
            close(fd);
            return NULL;
@@ -1110,6 +1377,8 @@ init_dag(Obj_Entry *root)
 {
     DoneList donelist;
 
+    if (root->dag_inited)
+       return;
     donelist_init(&donelist);
     init_dag1(root, root, &donelist);
 }
@@ -1121,11 +1390,13 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
 
     if (donelist_check(dlp, obj))
        return;
+
     objlist_push_tail(&obj->dldags, root);
     objlist_push_tail(&root->dagmembers, obj);
     for (needed = obj->needed;  needed != NULL;  needed = needed->next)
        if (needed->obj != NULL)
            init_dag1(root, needed->obj, dlp);
+    root->dag_inited = true;
 }
 
 /*
@@ -1141,8 +1412,8 @@ init_rtld(caddr_t mapbase)
     /*
      * Conjure up an Obj_Entry structure for the dynamic linker.
      *
-     * The "path" member can't be initialized yet because string constatns
-     * cannot yet be acessed. Below we will set it correctly.
+     * The "path" member can't be initialized yet because string constants
+     * cannot yet be accessed. Below we will set it correctly.
      */
     memset(&objtmp, 0, sizeof(objtmp));
     objtmp.path = NULL;
@@ -1151,7 +1422,7 @@ init_rtld(caddr_t mapbase)
 #ifdef PIC
     objtmp.relocbase = mapbase;
 #endif
-    if (&_DYNAMIC != 0) {
+    if (RTLD_IS_DYNAMIC()) {
        objtmp.dynamic = rtld_dynamic(&objtmp);
        digest_dynamic(&objtmp, 1);
        assert(objtmp.needed == NULL);
@@ -1208,9 +1479,9 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list)
 static void
 initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list)
 {
-    if (obj->init_done)
+    if (obj->init_scanned || obj->init_done)
        return;
-    obj->init_done = true;
+    obj->init_scanned = true;
 
     /* Recursively process the successor objects. */
     if (&obj->next != tail)
@@ -1221,14 +1492,20 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list)
        initlist_add_neededs(obj->needed, list);
 
     /* Add the object to the init list. */
-    if (obj->init != NULL)
+    if (obj->init != (Elf_Addr)NULL)
        objlist_push_tail(list, obj);
 
     /* Add the object to the global fini list in the reverse order. */
-    if (obj->fini != NULL)
+    if (obj->fini != (Elf_Addr)NULL && !obj->on_fini_list) {
        objlist_push_head(&list_fini, obj);
+       obj->on_fini_list = true;
+    }
 }
 
+#ifndef FPTR_TARGET
+#define FPTR_TARGET(f) ((Elf_Addr) (f))
+#endif
+
 static bool
 is_exported(const Elf_Sym *def)
 {
@@ -1236,10 +1513,9 @@ is_exported(const Elf_Sym *def)
     const func_ptr_type *p;
 
     value = (Elf_Addr)(obj_rtld.relocbase + def->st_value);
-    for (p = exports;  *p != NULL;  p++) {
-       if ((Elf_Addr)(*p) == value)
+    for (p = exports;  *p != NULL;  p++)
+       if (FPTR_TARGET(*p) == value)
            return true;
-    }
     return false;
 }
 
@@ -1249,30 +1525,27 @@ is_exported(const Elf_Sym *def)
  * returns -1 on failure.
  */
 static int
-load_needed_objects(Obj_Entry *first)
+load_needed_objects(Obj_Entry *first, int flags)
 {
-    Obj_Entry *obj;
+    Obj_Entry *obj, *obj1;
 
     for (obj = first;  obj != NULL;  obj = obj->next) {
        Needed_Entry *needed;
 
        for (needed = obj->needed;  needed != NULL;  needed = needed->next) {
-           const char *name = obj->strtab + needed->name;
-           char *path = find_library(name, obj);
-
-           needed->obj = NULL;
-           if (path == NULL && !ld_tracing)
+           obj1 = needed->obj = load_object(obj->strtab + needed->name, obj,
+               flags & ~RTLD_LO_NOLOAD);
+           if (obj1 == NULL && !ld_tracing)
                return -1;
-
-           if (path) {
-               needed->obj = load_object(path);
-               if (needed->obj == NULL && !ld_tracing)
-                   return -1;          /* XXX - cleanup */
+           if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) {
+               dbg("obj %s nodelete", obj1->path);
+               init_dag(obj1);
+               ref_dag(obj1);
+               obj1->ref_nodel = true;
            }
        }
     }
-
-    return 0;
+    return (0);
 }
 
 #define RTLD_FUNCTRACE "_rtld_functrace"
@@ -1289,16 +1562,13 @@ load_preload_objects(void)
     p += strspn(p, delim);
     while (*p != '\0') {
        size_t len = strcspn(p, delim);
-       char *path;
        char savech;
        Obj_Entry *obj;
        const Elf_Sym *sym;
 
        savech = p[len];
        p[len] = '\0';
-       if ((path = find_library(p, NULL)) == NULL)
-           return -1;
-       obj = load_object(path);
+       obj = load_object(p, NULL, 0);
        if (obj == NULL)
            return -1;  /* XXX - cleanup */
        p[len] = savech;
@@ -1306,138 +1576,134 @@ load_preload_objects(void)
        p += strspn(p, delim);
 
        /* Check for the magic tracing function */
-       sym = symlook_obj(RTLD_FUNCTRACE, elf_hash(RTLD_FUNCTRACE), obj, true);
+       sym = symlook_obj(RTLD_FUNCTRACE, elf_hash(RTLD_FUNCTRACE), obj, NULL, 1);
        if (sym != NULL) {
                rtld_functrace = (void *)(obj->relocbase + sym->st_value);
                rtld_functrace_obj = obj;
        }
     }
+    LD_UTRACE(UTRACE_PRELOAD_FINISHED, NULL, NULL, 0, 0, NULL);
     return 0;
 }
 
 /*
- * Returns a pointer to the Obj_Entry for the object with the given path.
- * Returns NULL if no matching object was found.
+ * Load a shared object into memory, if it is not already loaded.
+ *
+ * Returns a pointer to the Obj_Entry for the object.  Returns NULL
+ * on failure.
  */
 static Obj_Entry *
-find_object(const char *path)
+load_object(const char *name, const Obj_Entry *refobj, int flags)
 {
     Obj_Entry *obj;
+    int fd = -1;
+    struct stat sb;
+    char *path;
 
-    for (obj = obj_list->next;  obj != NULL;  obj = obj->next) {
-       if (strcmp(obj->path, path) == 0)
-           return(obj);
-    }
-    return(NULL);
-}
+    for (obj = obj_list->next;  obj != NULL;  obj = obj->next)
+       if (object_match_name(obj, name))
+           return obj;
 
-/*
- * Returns a pointer to the Obj_Entry for the object matching device and
- * inode of the given path. If no matching object was found, the descriptor
- * is returned in fd.
- * Returns with obj == NULL && fd == -1 on error.
- */
-static Obj_Entry *
-find_object2(const char *path, int *fd, struct stat *sb)
-{
-    Obj_Entry *obj;
+    path = find_library(name, refobj);
+    if (path == NULL)
+       return NULL;
 
-    if ((*fd = open(path, O_RDONLY)) == -1) {
+    /*
+     * If we didn't find a match by pathname, open the file and check
+     * again by device and inode.  This avoids false mismatches caused
+     * by multiple links or ".." in pathnames.
+     *
+     * To avoid a race, we open the file and use fstat() rather than
+     * using stat().
+     */
+    if ((fd = open(path, O_RDONLY)) == -1) {
        _rtld_error("Cannot open \"%s\"", path);
-       return(NULL);
+       free(path);
+       return NULL;
     }
-    if (fstat(*fd, sb) == -1) {
+    if (fstat(fd, &sb) == -1) {
        _rtld_error("Cannot fstat \"%s\"", path);
-       close(*fd);
-       *fd = -1;
+       close(fd);
+       free(path);
        return NULL;
     }
-    for (obj = obj_list->next;  obj != NULL;  obj = obj->next) {
-       if (obj->ino == sb->st_ino && obj->dev == sb->st_dev) {
-           close(*fd);
+    for (obj = obj_list->next;  obj != NULL;  obj = obj->next)
+       if (obj->ino == sb.st_ino && obj->dev == sb.st_dev)
            break;
-       }
+    if (obj != NULL) {
+       object_add_name(obj, name);
+       free(path);
+       close(fd);
+       return obj;
+    }
+    if (flags & RTLD_LO_NOLOAD) {
+       free(path);
+       return (NULL);
     }
 
-    return(obj);
+    /* First use of this object, so we must map it in */
+    obj = do_load_object(fd, name, path, &sb, flags);
+    if (obj == NULL)
+       free(path);
+    close(fd);
+
+    return obj;
 }
 
-/*
- * Load a shared object into memory, if it is not already loaded.  The
- * argument must be a string allocated on the heap.  This function assumes
- * responsibility for freeing it when necessary.
- *
- * Returns a pointer to the Obj_Entry for the object.  Returns NULL
- * on failure.
- */
 static Obj_Entry *
-load_object(char *path)
+do_load_object(int fd, const char *name, char *path, struct stat *sbp,
+  int flags)
 {
     Obj_Entry *obj;
-    int fd = -1;
-    struct stat sb;
-
-    obj = find_object(path);
-    if (obj != NULL) {
-       obj->refcount++;
-       free(path);
-       return(obj);
-    }
+    struct statfs fs;
 
-    obj = find_object2(path, &fd, &sb);
-    if (obj != NULL) {
-       obj->refcount++;
-       free(path);
-       return(obj);
-    } else if (fd == -1) {
-       free(path);
-       return(NULL);
+    /*
+     * but first, make sure that environment variables haven't been
+     * used to circumvent the noexec flag on a filesystem.
+     */
+    if (dangerous_ld_env) {
+       if (fstatfs(fd, &fs) != 0) {
+           _rtld_error("Cannot fstatfs \"%s\"", path);
+               return NULL;
+       }
+       if (fs.f_flags & MNT_NOEXEC) {
+           _rtld_error("Cannot execute objects on %s\n", fs.f_mntonname);
+           return NULL;
+       }
     }
     dbg("loading \"%s\"", path);
-    obj = map_object(fd, path, &sb);
-    close(fd);
-    if (obj == NULL) {
-       free(path);
+    obj = map_object(fd, path, sbp);
+    if (obj == NULL)
         return NULL;
-    }
 
+    object_add_name(obj, name);
     obj->path = path;
     digest_dynamic(obj, 0);
+    if (obj->z_noopen && (flags & (RTLD_LO_DLOPEN | RTLD_LO_TRACE)) ==
+      RTLD_LO_DLOPEN) {
+       dbg("refusing to load non-loadable \"%s\"", obj->path);
+       _rtld_error("Cannot dlopen non-loadable %s", obj->path);
+       munmap(obj->mapbase, obj->mapsize);
+       obj_free(obj);
+       return (NULL);
+    }
 
     *obj_tail = obj;
     obj_tail = &obj->next;
     obj_count++;
+    obj_loads++;
     linkmap_add(obj);  /* for GDB & dlinfo() */
 
     dbg("  %p .. %p: %s", obj->mapbase,
          obj->mapbase + obj->mapsize - 1, obj->path);
     if (obj->textrel)
-        dbg("  WARNING: %s has impure text", obj->path);
+       dbg("  WARNING: %s has impure text", obj->path);
+    LD_UTRACE(UTRACE_LOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0,
+       obj->path);
 
-    obj->refcount++;
     return obj;
 }
 
-/*
- * Check for locking violations and die if one is found.
- */
-static void
-lock_check(void)
-{
-    int rcount, wcount;
-
-    rcount = lockinfo.rcount;
-    wcount = lockinfo.wcount;
-    assert(rcount >= 0);
-    assert(wcount >= 0);
-    if (wcount > 1 || (wcount != 0 && rcount != 0)) {
-       _rtld_error("Application locking error: %d readers and %d writers"
-         " in dynamic linker.  See DLLOCKINIT(3) in manual pages.",
-         rcount, wcount);
-       die();
-    }
-}
-
 static Obj_Entry *
 obj_from_addr(const void *addr)
 {
@@ -1454,26 +1720,56 @@ obj_from_addr(const void *addr)
 
 /*
  * Call the finalization functions for each of the objects in "list"
- * which are unreferenced.  All of the objects are expected to have
- * non-NULL fini functions.
+ * belonging to the DAG of "root" and referenced once. If NULL "root"
+ * is specified, every finalization function will be called regardless
+ * of the reference count and the list elements won't be freed. All of
+ * the objects are expected to have non-NULL fini functions.
  */
 static void
-objlist_call_fini(Objlist *list)
+objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate)
 {
     Objlist_Entry *elm;
     char *saved_msg;
 
+    assert(root == NULL || root->refcount == 1);
+
     /*
      * Preserve the current error message since a fini function might
      * call into the dynamic linker and overwrite it.
      */
     saved_msg = errmsg_save();
-    STAILQ_FOREACH(elm, list, link) {
-       if (elm->obj->refcount == 0) {
-           dbg("calling fini function for %s", elm->obj->path);
-           (*elm->obj->fini)();
+    do {
+       STAILQ_FOREACH(elm, list, link) {
+           if (root != NULL && (elm->obj->refcount != 1 ||
+             objlist_find(&root->dagmembers, elm->obj) == NULL))
+               continue;
+           dbg("calling fini function for %s at %p", elm->obj->path,
+               (void *)elm->obj->fini);
+           LD_UTRACE(UTRACE_FINI_CALL, elm->obj, (void *)elm->obj->fini, 0, 0,
+               elm->obj->path);
+           /* Remove object from fini list to prevent recursive invocation. */
+           STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link);
+           /*
+            * XXX: If a dlopen() call references an object while the
+            * fini function is in progress, we might end up trying to
+            * unload the referenced object in dlclose() or the object
+            * won't be unloaded although its fini function has been
+            * called.
+            */
+           lock_release(rtld_bind_lock, lockstate);
+           call_initfini_pointer(elm->obj, elm->obj->fini);
+           wlock_acquire(rtld_bind_lock, lockstate);
+           /* No need to free anything if process is going down. */
+           if (root != NULL)
+               free(elm);
+           /*
+            * We must restart the list traversal after every fini call
+            * because a dlclose() call from the fini function or from
+            * another thread might have modified the reference counts.
+            */
+           break;
        }
-    }
+    } while (elm != NULL);
     errmsg_restore(saved_msg);
 }
 
@@ -1483,19 +1779,41 @@ objlist_call_fini(Objlist *list)
  * functions.
  */
 static void
-objlist_call_init(Objlist *list)
+objlist_call_init(Objlist *list, RtldLockState *lockstate)
 {
     Objlist_Entry *elm;
+    Obj_Entry *obj;
     char *saved_msg;
 
+    /*
+     * Clean init_scanned flag so that objects can be rechecked and
+     * possibly initialized earlier if any of vectors called below
+     * cause the change by using dlopen.
+     */
+    for (obj = obj_list;  obj != NULL;  obj = obj->next)
+       obj->init_scanned = false;
+
     /*
      * Preserve the current error message since an init function might
      * call into the dynamic linker and overwrite it.
      */
     saved_msg = errmsg_save();
     STAILQ_FOREACH(elm, list, link) {
-       dbg("calling init function for %s", elm->obj->path);
-       (*elm->obj->init)();
+       if (elm->obj->init_done) /* Initialized early. */
+           continue;
+       dbg("calling init function for %s at %p", elm->obj->path,
+           (void *)elm->obj->init);
+       LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)elm->obj->init, 0, 0,
+           elm->obj->path);
+       /*
+        * Race: other thread might try to use this object before current
+        * one completes the initilization. Not much can be done here
+        * without better locking.
+        */
+       elm->obj->init_done = true;
+       lock_release(rtld_bind_lock, lockstate);
+       call_initfini_pointer(elm->obj, elm->obj->init);
+       wlock_acquire(rtld_bind_lock, lockstate);
     }
     errmsg_restore(saved_msg);
 }
@@ -1560,27 +1878,6 @@ objlist_remove(Objlist *list, Obj_Entry *obj)
     }
 }
 
-/*
- * Remove all of the unreferenced objects from "list".
- */
-static void
-objlist_remove_unref(Objlist *list)
-{
-    Objlist newlist;
-    Objlist_Entry *elm;
-
-    STAILQ_INIT(&newlist);
-    while (!STAILQ_EMPTY(list)) {
-       elm = STAILQ_FIRST(list);
-       STAILQ_REMOVE_HEAD(list, link);
-       if (elm->obj->refcount == 0)
-           free(elm);
-       else
-           STAILQ_INSERT_TAIL(&newlist, elm, link);
-    }
-    *list = newlist;
-}
-
 /*
  * Relocate newly-loaded shared objects.  The argument is a pointer to
  * the Obj_Entry for the first such object.  All objects from the first
@@ -1670,14 +1967,15 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj)
 static void
 rtld_exit(void)
 {
-    Obj_Entry *obj;
+    RtldLockState lockstate;
 
+    wlock_acquire(rtld_bind_lock, &lockstate);
     dbg("rtld_exit()");
-    /* Clear all the reference counts so the fini functions will be called. */
-    for (obj = obj_list;  obj != NULL;  obj = obj->next)
-       obj->refcount = 0;
-    objlist_call_fini(&list_fini);
+    objlist_call_fini(&list_fini, NULL, &lockstate);
     /* No need to remove the items from the list, since we are exiting. */
+    if (!libmap_disable)
+        lm_fini();
+    lock_release(rtld_bind_lock, &lockstate);
 }
 
 static void *
@@ -1763,39 +2061,42 @@ int
 dlclose(void *handle)
 {
     Obj_Entry *root;
+    RtldLockState lockstate;
 
-    wlock_acquire();
+    wlock_acquire(rtld_bind_lock, &lockstate);
     root = dlcheck(handle);
     if (root == NULL) {
-       wlock_release();
+       lock_release(rtld_bind_lock, &lockstate);
        return -1;
     }
+    LD_UTRACE(UTRACE_DLCLOSE_START, handle, NULL, 0, root->dl_refcount,
+       root->path);
 
     /* Unreference the object and its dependencies. */
     root->dl_refcount--;
 
-    unref_dag(root);
-
-    if (root->refcount == 0) {
+    if (root->refcount == 1) {
        /*
-        * The object is no longer referenced, so we must unload it.
-        * First, call the fini functions with no locks held.
+        * The object will be no longer referenced, so we must unload it.
+        * First, call the fini functions.
         */
-       wlock_release();
-       objlist_call_fini(&list_fini);
-       wlock_acquire();
-       objlist_remove_unref(&list_fini);
+       objlist_call_fini(&list_fini, root, &lockstate);
+
+       unref_dag(root);
 
        /* Finish cleaning up the newly-unreferenced objects. */
        GDB_STATE(RT_DELETE,&root->linkmap);
        unload_object(root);
        GDB_STATE(RT_CONSISTENT,NULL);
-    }
-    wlock_release();
+    } else
+       unref_dag(root);
+
+    LD_UTRACE(UTRACE_DLCLOSE_STOP, handle, NULL, 0, 0, NULL);
+    lock_release(rtld_bind_lock, &lockstate);
     return 0;
 }
 
-const char *
+char *
 dlerror(void)
 {
     char *msg = error_message;
@@ -1809,15 +2110,24 @@ dlopen(const char *name, int mode)
     Obj_Entry **old_obj_tail;
     Obj_Entry *obj;
     Objlist initlist;
-    int result;
+    RtldLockState lockstate;
+    int result, lo_flags;
 
+    LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name);
     ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
     if (ld_tracing != NULL)
        environ = (char **)*get_program_var_addr("environ");
+    lo_flags = RTLD_LO_DLOPEN;
+    if (mode & RTLD_NODELETE)
+           lo_flags |= RTLD_LO_NODELETE;
+    if (mode & RTLD_NOLOAD)
+           lo_flags |= RTLD_LO_NOLOAD;
+    if (ld_tracing != NULL)
+           lo_flags |= RTLD_LO_TRACE;
 
     objlist_init(&initlist);
 
-    wlock_acquire();
+    wlock_acquire(rtld_bind_lock, &lockstate);
     GDB_STATE(RT_ADD,NULL);
 
     old_obj_tail = obj_tail;
@@ -1826,9 +2136,7 @@ dlopen(const char *name, int mode)
        obj = obj_main;
        obj->refcount++;
     } else {
-       char *path = find_library(name, obj_main);
-       if (path != NULL)
-           obj = load_object(path);
+       obj = load_object(name, obj_main, lo_flags);
     }
 
     if (obj) {
@@ -1838,13 +2146,15 @@ dlopen(const char *name, int mode)
        mode &= RTLD_MODEMASK;
        if (*old_obj_tail != NULL) {            /* We loaded something new. */
            assert(*old_obj_tail == obj);
-           result = load_needed_objects(obj);
+           result = load_needed_objects(obj, RTLD_LO_DLOPEN);
+           init_dag(obj);
+           ref_dag(obj);
+           if (result != -1)
+               result = rtld_verify_versions(&obj->dagmembers);
            if (result != -1 && ld_tracing)
                goto trace;
-
            if (result == -1 ||
-             (init_dag(obj), relocate_objects(obj, mode == RTLD_NOW,
-              &obj_rtld)) == -1) {
+             (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld)) == -1) {
                obj->dl_refcount--;
                unref_dag(obj);
                if (obj->refcount == 0)
@@ -1854,100 +2164,208 @@ dlopen(const char *name, int mode)
                /* Make list of init functions to call. */
                initlist_add_objects(obj, &obj->next, &initlist);
            }
-       } else if (ld_tracing)
-           goto trace;
+       } else {
+
+           /*
+            * Bump the reference counts for objects on this DAG.  If
+            * this is the first dlopen() call for the object that was
+            * already loaded as a dependency, initialize the dag
+            * starting at it.
+            */
+           init_dag(obj);
+           ref_dag(obj);
+
+           if ((lo_flags & RTLD_LO_TRACE) != 0)
+               goto trace;
+       }
+       if (obj != NULL && ((lo_flags & RTLD_LO_NODELETE) != 0 ||
+         obj->z_nodelete) && !obj->ref_nodel) {
+           dbg("obj %s nodelete", obj->path);
+           ref_dag(obj);
+           obj->z_nodelete = obj->ref_nodel = true;
+       }
     }
 
+    LD_UTRACE(UTRACE_DLOPEN_STOP, obj, NULL, 0, obj ? obj->dl_refcount : 0,
+       name);
     GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
 
-    /* Call the init functions with no locks held. */
-    wlock_release();
-    objlist_call_init(&initlist);
-    wlock_acquire();
+    /* Call the init functions. */
+    objlist_call_init(&initlist, &lockstate);
     objlist_clear(&initlist);
-    wlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
     return obj;
 trace:
     trace_loaded_objects(obj);
-    wlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
     exit(0);
 }
 
-void *
-dlsym(void *handle, const char *name)
+static void *
+do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
+    int flags)
 {
-    const Obj_Entry *obj;
+    DoneList donelist;
+    const Obj_Entry *obj, *defobj;
+    const Elf_Sym *def, *symp;
     unsigned long hash;
-    const Elf_Sym *def;
-    const Obj_Entry *defobj;
+    RtldLockState lockstate;
 
     hash = elf_hash(name);
     def = NULL;
     defobj = NULL;
+    flags |= SYMLOOK_IN_PLT;
 
-    rlock_acquire();
+    rlock_acquire(rtld_bind_lock, &lockstate);
+    if (sigsetjmp(lockstate.env, 0) != 0)
+           lock_upgrade(rtld_bind_lock, &lockstate);
     if (handle == NULL || handle == RTLD_NEXT ||
        handle == RTLD_DEFAULT || handle == RTLD_SELF) {
-       void *retaddr;
 
-       retaddr = __builtin_return_address(0);  /* __GNUC__ only */
        if ((obj = obj_from_addr(retaddr)) == NULL) {
            _rtld_error("Cannot determine caller's shared object");
-           rlock_release();
+           lock_release(rtld_bind_lock, &lockstate);
            return NULL;
        }
        if (handle == NULL) {   /* Just the caller's shared object. */
-           def = symlook_obj(name, hash, obj, true);
+           def = symlook_obj(name, hash, obj, ve, flags);
            defobj = obj;
        } else if (handle == RTLD_NEXT || /* Objects after caller's */
                   handle == RTLD_SELF) { /* ... caller included */
            if (handle == RTLD_NEXT)
                obj = obj->next;
            for (; obj != NULL; obj = obj->next) {
-               if ((def = symlook_obj(name, hash, obj, true)) != NULL) {
-                   defobj = obj;
-                   break;
+               if ((symp = symlook_obj(name, hash, obj, ve, flags)) != NULL) {
+                   if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
+                       def = symp;
+                       defobj = obj;
+                       if (ELF_ST_BIND(def->st_info) != STB_WEAK)
+                           break;
+                   }
+               }
+           }
+           /*
+            * Search the dynamic linker itself, and possibly resolve the
+            * symbol from there.  This is how the application links to
+            * dynamic linker services such as dlopen.
+            */
+           if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+               symp = symlook_obj(name, hash, &obj_rtld, ve, flags);
+               if (symp != NULL) {
+                   def = symp;
+                   defobj = &obj_rtld;
                }
            }
        } else {
            assert(handle == RTLD_DEFAULT);
-           def = symlook_default(name, hash, obj, &defobj, true);
+           def = symlook_default(name, hash, obj, &defobj, ve, flags);
        }
     } else {
-       DoneList donelist;
-
        if ((obj = dlcheck(handle)) == NULL) {
-           rlock_release();
+           lock_release(rtld_bind_lock, &lockstate);
            return NULL;
        }
 
        donelist_init(&donelist);
        if (obj->mainprog) {
            /* Search main program and all libraries loaded by it. */
-           def = symlook_list(name, hash, &list_main, &defobj, true,
-             &donelist);
+           def = symlook_list(name, hash, &list_main, &defobj, ve, flags,
+                              &donelist);
+
+           /*
+            * We do not distinguish between 'main' object and global scope.
+            * If symbol is not defined by objects loaded at startup, continue
+            * search among dynamically loaded objects with RTLD_GLOBAL
+            * scope.
+            */
+           if (def == NULL)
+               def = symlook_list(name, hash, &list_global, &defobj, ve,
+                                  flags, &donelist);
        } else {
            Needed_Entry fake;
 
-           /* Search the given object and its needed objects. */
+           /* Search the whole DAG rooted at the given object. */
            fake.next = NULL;
            fake.obj = (Obj_Entry *)obj;
            fake.name = 0;
-           def = symlook_needed(name, hash, &fake, &defobj, true,
-             &donelist);
+           def = symlook_needed(name, hash, &fake, &defobj, ve, flags,
+                                &donelist);
        }
     }
 
     if (def != NULL) {
-       rlock_release();
-       return defobj->relocbase + def->st_value;
+       lock_release(rtld_bind_lock, &lockstate);
+
+       /*
+        * The value required by the caller is derived from the value
+        * of the symbol. For the ia64 architecture, we need to
+        * construct a function descriptor which the caller can use to
+        * call the function with the right 'gp' value. For other
+        * architectures and for non-functions, the value is simply
+        * the relocated value of the symbol.
+        */
+       if (ELF_ST_TYPE(def->st_info) == STT_FUNC)
+           return make_function_pointer(def, defobj);
+       else
+           return defobj->relocbase + def->st_value;
     }
 
     _rtld_error("Undefined symbol \"%s\"", name);
-    rlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
     return NULL;
 }
 
+void *
+dlsym(void *handle, const char *name)
+{
+       return do_dlsym(handle, name, __builtin_return_address(0), NULL,
+           SYMLOOK_DLSYM);
+}
+
+dlfunc_t
+dlfunc(void *handle, const char *name)
+{
+       union {
+               void *d;
+               dlfunc_t f;
+       } rv;
+
+       rv.d = do_dlsym(handle, name, __builtin_return_address(0), NULL,
+           SYMLOOK_DLSYM);
+       return (rv.f);
+}
+
+void *
+dlvsym(void *handle, const char *name, const char *version)
+{
+       Ver_Entry ventry;
+
+       ventry.name = version;
+       ventry.file = NULL;
+       ventry.hash = elf_hash(version);
+       ventry.flags= 0;
+       return do_dlsym(handle, name, __builtin_return_address(0), &ventry,
+           SYMLOOK_DLSYM);
+}
+
+int
+_rtld_addr_phdr(const void *addr, struct dl_phdr_info *phdr_info)
+{
+    const Obj_Entry *obj;
+    RtldLockState lockstate;
+
+    rlock_acquire(rtld_bind_lock, &lockstate);
+    obj = obj_from_addr(addr);
+    if (obj == NULL) {
+        _rtld_error("No shared object contains address");
+       lock_release(rtld_bind_lock, &lockstate);
+        return (0);
+    }
+    rtld_fill_dl_phdr_info(obj, phdr_info);
+    lock_release(rtld_bind_lock, &lockstate);
+    return (1);
+}
+
 int
 dladdr(const void *addr, Dl_info *info)
 {
@@ -1955,12 +2373,13 @@ dladdr(const void *addr, Dl_info *info)
     const Elf_Sym *def;
     void *symbol_addr;
     unsigned long symoffset;
-    rlock_acquire();
+    RtldLockState lockstate;
+
+    rlock_acquire(rtld_bind_lock, &lockstate);
     obj = obj_from_addr(addr);
     if (obj == NULL) {
         _rtld_error("No shared object contains address");
-       rlock_release();
+       lock_release(rtld_bind_lock, &lockstate);
         return 0;
     }
     info->dli_fname = obj->path;
@@ -1999,7 +2418,7 @@ dladdr(const void *addr, Dl_info *info)
         if (info->dli_saddr == addr)
             break;
     }
-    rlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
     return 1;
 }
 
@@ -2007,9 +2426,10 @@ int
 dlinfo(void *handle, int request, void *p)
 {
     const Obj_Entry *obj;
+    RtldLockState lockstate;
     int error;
 
-    rlock_acquire();
+    rlock_acquire(rtld_bind_lock, &lockstate);
 
     if (handle == NULL || handle == RTLD_SELF) {
        void *retaddr;
@@ -2021,7 +2441,7 @@ dlinfo(void *handle, int request, void *p)
        obj = dlcheck(handle);
 
     if (obj == NULL) {
-       rlock_release();
+       lock_release(rtld_bind_lock, &lockstate);
        return (-1);
     }
 
@@ -2044,7 +2464,47 @@ dlinfo(void *handle, int request, void *p)
        error = -1;
     }
 
-    rlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
+
+    return (error);
+}
+
+static void
+rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info)
+{
+
+       phdr_info->dlpi_addr = (Elf_Addr)obj->relocbase;
+       phdr_info->dlpi_name = STAILQ_FIRST(&obj->names) ?
+           STAILQ_FIRST(&obj->names)->name : obj->path;
+       phdr_info->dlpi_phdr = obj->phdr;
+       phdr_info->dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
+       phdr_info->dlpi_tls_modid = obj->tlsindex;
+       phdr_info->dlpi_tls_data = obj->tlsinit;
+       phdr_info->dlpi_adds = obj_loads;
+       phdr_info->dlpi_subs = obj_loads - obj_count;
+}
+
+int
+dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param)
+{
+    struct dl_phdr_info phdr_info;
+    const Obj_Entry *obj;
+    RtldLockState bind_lockstate, phdr_lockstate;
+    int error;
+
+    wlock_acquire(rtld_phdr_lock, &phdr_lockstate);
+    rlock_acquire(rtld_bind_lock, &bind_lockstate);
+
+    error = 0;
+
+    for (obj = obj_list;  obj != NULL;  obj = obj->next) {
+       rtld_fill_dl_phdr_info(obj, &phdr_info);
+       if ((error = callback(&phdr_info, sizeof phdr_info, param)) != 0)
+               break;
+
+    }
+    lock_release(rtld_bind_lock, &bind_lockstate);
+    lock_release(rtld_phdr_lock, &phdr_lockstate);
 
     return (error);
 }
@@ -2066,7 +2526,7 @@ fill_search_info(const char *dir, size_t dirlen, void *param)
 
     if (arg->request == RTLD_DI_SERINFOSIZE) {
        arg->serinfo->dls_cnt ++;
-       arg->serinfo->dls_size += dirlen + 1;
+       arg->serinfo->dls_size += sizeof(Dl_serpath) + dirlen + 1;
     } else {
        struct dl_serpath *s_entry;
 
@@ -2179,6 +2639,23 @@ rtld_dirname(const char *path, char *bname)
     return (0);
 }
 
+static int
+rtld_dirname_abs(const char *path, char *base)
+{
+       char base_rel[PATH_MAX];
+
+       if (rtld_dirname(path, base) == -1)
+               return (-1);
+       if (base[0] == '/')
+               return (0);
+       if (getcwd(base_rel, sizeof(base_rel)) == NULL ||
+           strlcat(base_rel, "/", sizeof(base_rel)) >= sizeof(base_rel) ||
+           strlcat(base_rel, base, sizeof(base_rel)) >= sizeof(base_rel))
+               return (-1);
+       strcpy(base, base_rel);
+       return (0);
+}
+
 static void
 linkmap_add(Obj_Entry *obj)
 {
@@ -2261,14 +2738,14 @@ get_program_var_addr(const char *name)
     for (obj = obj_main;  obj != NULL;  obj = obj->next) {
        const Elf_Sym *def;
 
-       if ((def = symlook_obj(name, hash, obj, false)) != NULL) {
+       if ((def = symlook_obj(name, hash, obj, NULL, 0)) != NULL) {
            const void **addr;
 
            addr = (const void **)(obj->relocbase + def->st_value);
            return addr;
        }
     }
-    return NULL;
+    return (NULL);
 }
 
 /*
@@ -2324,8 +2801,8 @@ _getenv_ld(const char *id)
  * defining object via the reference parameter DEFOBJ_OUT.
  */
 static const Elf_Sym *
-symlook_default(const char *name, unsigned long hash,
-    const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
+symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj,
+    const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags)
 {
     DoneList donelist;
     const Elf_Sym *def;
@@ -2339,7 +2816,7 @@ symlook_default(const char *name, unsigned long hash,
 
     /* Look first in the referencing object if linked symbolically. */
     if (refobj->symbolic && !donelist_check(&donelist, refobj)) {
-       symp = symlook_obj(name, hash, refobj, in_plt);
+       symp = symlook_obj(name, hash, refobj, ventry, flags);
        if (symp != NULL) {
            def = symp;
            defobj = refobj;
@@ -2348,7 +2825,8 @@ symlook_default(const char *name, unsigned long hash,
 
     /* Search all objects loaded at program start up. */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-       symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist);
+       symp = symlook_list(name, hash, &list_main, &obj, ventry, flags,
+           &donelist);
        if (symp != NULL &&
          (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
            def = symp;
@@ -2360,8 +2838,8 @@ symlook_default(const char *name, unsigned long hash,
     STAILQ_FOREACH(elm, &list_global, link) {
        if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
            break;
-       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
-         &donelist);
+       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry,
+          flags, &donelist);
        if (symp != NULL &&
          (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
            def = symp;
@@ -2373,8 +2851,8 @@ symlook_default(const char *name, unsigned long hash,
     STAILQ_FOREACH(elm, &refobj->dldags, link) {
        if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
            break;
-       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
-         &donelist);
+       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry,
+           flags, &donelist);
        if (symp != NULL &&
          (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
            def = symp;
@@ -2389,7 +2867,7 @@ symlook_default(const char *name, unsigned long hash,
      * in the "exports" array can be resolved from the dynamic linker.
      */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-       symp = symlook_obj(name, hash, &obj_rtld, in_plt);
+       symp = symlook_obj(name, hash, &obj_rtld, ventry, flags);
        if (symp != NULL && is_exported(symp)) {
            def = symp;
            defobj = &obj_rtld;
@@ -2403,7 +2881,8 @@ symlook_default(const char *name, unsigned long hash,
 
 static const Elf_Sym *
 symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
-  const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
+  const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags,
+  DoneList *dlp)
 {
     const Elf_Sym *symp;
     const Elf_Sym *def;
@@ -2415,7 +2894,7 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
     STAILQ_FOREACH(elm, objlist, link) {
        if (donelist_check(dlp, elm->obj))
            continue;
-       if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) {
+       if ((symp = symlook_obj(name, hash, elm->obj, ventry, flags)) != NULL) {
            if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
                def = symp;
                defobj = elm->obj;
@@ -2437,23 +2916,24 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
  */
 static const Elf_Sym *
 symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed,
-  const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
+  const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags,
+  DoneList *dlp)
 {
     const Elf_Sym *def, *def_w;
     const Needed_Entry *n;
     const Obj_Entry *obj, *defobj, *defobj1;
-    
+
     def = def_w = NULL;
     defobj = NULL;
     for (n = needed; n != NULL; n = n->next) {
-        if ((obj = n->obj) == NULL ||
-            donelist_check(dlp, obj) ||
-            (def = symlook_obj(name, hash, obj, in_plt)) == NULL)
-                continue;
-        defobj = obj;
-        if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
-            *defobj_out = defobj;
-            return (def);
+       if ((obj = n->obj) == NULL ||
+           donelist_check(dlp, obj) ||
+           (def = symlook_obj(name, hash, obj, ventry, flags)) == NULL)
+           continue;
+       defobj = obj;
+       if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
+           *defobj_out = defobj;
+           return (def);
        }
     }
     /*
@@ -2461,64 +2941,149 @@ symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed,
      * directly needed objects, or found symbol is weak.
      */
     for (n = needed; n != NULL; n = n->next) {
-        if ((obj = n->obj) == NULL)
-            continue;
-        def_w = symlook_needed(name, hash, obj->needed, &defobj1,
-                              in_plt, dlp);
-        if (def_w == NULL)
-            continue;
-        if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
-            def = def_w;
-            defobj = defobj1;
-        }
-        if (ELF_ST_BIND(def_w->st_info) != STB_WEAK)
-            break;
+       if ((obj = n->obj) == NULL)
+           continue;
+       def_w = symlook_needed(name, hash, obj->needed, &defobj1,
+                              ventry, flags, dlp);
+       if (def_w == NULL)
+           continue;
+       if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
+           def = def_w;
+           defobj = defobj1;
+       }
+       if (ELF_ST_BIND(def_w->st_info) != STB_WEAK)
+           break;
     }
     if (def != NULL)
-        *defobj_out = defobj;
-    return def;
+       *defobj_out = defobj;
+    return (def);
 }
 
 /*
  * Search the symbol table of a single shared object for a symbol of
- * the given name.  Returns a pointer to the symbol, or NULL if no
- * definition was found.
+ * the given name and version, if requested.  Returns a pointer to the
+ * symbol, or NULL if no definition was found.
  *
  * The symbol's hash value is passed in for efficiency reasons; that
  * eliminates many recomputations of the hash value.
  */
 const Elf_Sym *
 symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj,
-  bool in_plt)
+    const Ver_Entry *ventry, int flags)
 {
-    if (obj->buckets != NULL) {
-       unsigned long symnum = obj->buckets[hash % obj->nbuckets];
+    unsigned long symnum;
+    const Elf_Sym *vsymp;
+    Elf_Versym verndx;
+    int vcount;
 
-       while (symnum != STN_UNDEF) {
-           const Elf_Sym *symp;
-           const char *strp;
-
-           if (symnum >= obj->nchains)
-               return NULL;    /* Bad object */
-
-           symp = obj->symtab + symnum;
-           strp = obj->strtab + symp->st_name;
+    if (obj->buckets == NULL)
+       return NULL;
 
-           if (name[0] == strp[0] && strcmp(name, strp) == 0)
-               return symp->st_shndx != SHN_UNDEF ||
-                 (!in_plt && symp->st_value != 0 &&
-                 ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
+    vsymp = NULL;
+    vcount = 0;
+    symnum = obj->buckets[hash % obj->nbuckets];
+
+    for (; symnum != STN_UNDEF; symnum = obj->chains[symnum]) {
+       const Elf_Sym *symp;
+       const char *strp;
+
+       if (symnum >= obj->nchains)
+           return NULL;        /* Bad object */
+
+       symp = obj->symtab + symnum;
+       strp = obj->strtab + symp->st_name;
+
+       switch (ELF_ST_TYPE(symp->st_info)) {
+       case STT_FUNC:
+       case STT_NOTYPE:
+       case STT_OBJECT:
+           if (symp->st_value == 0)
+               continue;
+               /* fallthrough */
+       case STT_TLS:
+           if (symp->st_shndx != SHN_UNDEF)
+               break;
+           else if (((flags & SYMLOOK_IN_PLT) == 0) &&
+                (ELF_ST_TYPE(symp->st_info) == STT_FUNC))
+               break;
+               /* fallthrough */
+       default:
+           continue;
+       }
+       if (name[0] != strp[0] || strcmp(name, strp) != 0)
+           continue;
 
-           symnum = obj->chains[symnum];
+       if (ventry == NULL) {
+           if (obj->versyms != NULL) {
+               verndx = VER_NDX(obj->versyms[symnum]);
+               if (verndx > obj->vernum) {
+                   _rtld_error("%s: symbol %s references wrong version %d",
+                       obj->path, obj->strtab + symnum, verndx);
+                   continue;
+               }
+               /*
+                * If we are not called from dlsym (i.e. this is a normal
+                * relocation from unversioned binary), accept the symbol
+                * immediately if it happens to have first version after
+                * this shared object became versioned. Otherwise, if
+                * symbol is versioned and not hidden, remember it. If it
+                * is the only symbol with this name exported by the
+                * shared object, it will be returned as a match at the
+                * end of the function. If symbol is global (verndx < 2)
+                * accept it unconditionally.
+                */
+               if ((flags & SYMLOOK_DLSYM) == 0 && verndx == VER_NDX_GIVEN)
+                   return symp;
+               else if (verndx >= VER_NDX_GIVEN) {
+                   if ((obj->versyms[symnum] & VER_NDX_HIDDEN) == 0) {
+                       if (vsymp == NULL)
+                           vsymp = symp;
+                       vcount ++;
+                   }
+                   continue;
+               }
+           }
+           return symp;
+       } else {
+           if (obj->versyms == NULL) {
+               if (object_match_name(obj, ventry->name)) {
+                   _rtld_error("%s: object %s should provide version %s for "
+                       "symbol %s", obj_rtld.path, obj->path, ventry->name,
+                       obj->strtab + symnum);
+                   continue;
+               }
+           } else {
+               verndx = VER_NDX(obj->versyms[symnum]);
+               if (verndx > obj->vernum) {
+                   _rtld_error("%s: symbol %s references wrong version %d",
+                       obj->path, obj->strtab + symnum, verndx);
+                   continue;
+               }
+               if (obj->vertab[verndx].hash != ventry->hash ||
+                   strcmp(obj->vertab[verndx].name, ventry->name)) {
+                   /*
+                    * Version does not match. Look if this is a global symbol
+                    * and if it is not hidden. If global symbol (verndx < 2)
+                    * is available, use it. Do not return symbol if we are
+                    * called by dlvsym, because dlvsym looks for a specific
+                    * version and default one is not what dlvsym wants.
+                    */
+                   if ((flags & SYMLOOK_DLSYM) ||
+                       (obj->versyms[symnum] & VER_NDX_HIDDEN) ||
+                       (verndx >= VER_NDX_GIVEN))
+                       continue;
+               }
+           }
+           return symp;
        }
     }
-    return NULL;
+    return (vcount == 1) ? vsymp : NULL;
 }
 
 static void
 trace_loaded_objects(Obj_Entry *obj)
 {
-    const char *fmt1, *fmt2, *fmt, *main_local;
+    const char *fmt1, *fmt2, *fmt, *main_local, *list_containers;
     int                c;
 
     if ((main_local = _getenv_ld("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL)
@@ -2530,14 +3095,18 @@ trace_loaded_objects(Obj_Entry *obj)
     if ((fmt2 = _getenv_ld("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL)
        fmt2 = "\t%o (%x)\n";
 
+    list_containers = _getenv_ld("LD_TRACE_LOADED_OBJECTS_ALL");
+
     for (; obj; obj = obj->next) {
        Needed_Entry            *needed;
        char                    *name, *path;
        bool                    is_lib;
 
+       if (list_containers && obj->needed != NULL)
+           printf("%s:\n", obj->path);
        for (needed = obj->needed; needed; needed = needed->next) {
            if (needed->obj != NULL) {
-               if (needed->obj->traced)
+               if (needed->obj->traced && !list_containers)
                    continue;
                needed->obj->traced = true;
                path = needed->obj->path;
@@ -2582,14 +3151,6 @@ trace_loaded_objects(Obj_Entry *obj)
                    case 'o':
                        printf("%s", name);
                        break;
-#if 0
-                   case 'm':
-                       printf("%d", sodp->sod_major);
-                       break;
-                   case 'n':
-                       printf("%d", sodp->sod_minor);
-                       break;
-#endif
                    case 'p':
                        printf("%s", path);
                        break;
@@ -2622,13 +3183,15 @@ unload_object(Obj_Entry *root)
     /*
      * Pass over the DAG removing unreferenced objects from
      * appropriate lists.
-     */ 
+     */
     unlink_object(root);
 
     /* Unmap all objects that are no longer referenced. */
     linkp = &obj_list->next;
     while ((obj = *linkp) != NULL) {
        if (obj->refcount == 0) {
+           LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0,
+               obj->path);
            dbg("unloading \"%s\"", obj->path);
            munmap(obj->mapbase, obj->mapsize);
            linkmap_delete(obj);
@@ -2644,7 +3207,6 @@ unload_object(Obj_Entry *root)
 static void
 unlink_object(Obj_Entry *root)
 {
-    const Needed_Entry *needed;
     Objlist_Entry *elm;
 
     if (root->refcount == 0) {
@@ -2652,44 +3214,49 @@ unlink_object(Obj_Entry *root)
        objlist_remove(&list_global, root);
 
        /* Remove the object from all objects' DAG lists. */
-       STAILQ_FOREACH(elm, &root->dagmembers , link)
+       STAILQ_FOREACH(elm, &root->dagmembers, link) {
            objlist_remove(&elm->obj->dldags, root);
+           if (elm->obj != root)
+               unlink_object(elm->obj);
+       }
     }
+}
 
-    for (needed = root->needed;  needed != NULL;  needed = needed->next)
-       if (needed->obj != NULL)
-           unlink_object(needed->obj);
+static void
+ref_dag(Obj_Entry *root)
+{
+    Objlist_Entry *elm;
+
+    assert(root->dag_inited);
+    STAILQ_FOREACH(elm, &root->dagmembers, link)
+       elm->obj->refcount++;
 }
 
 static void
 unref_dag(Obj_Entry *root)
 {
-    const Needed_Entry *needed;
+    Objlist_Entry *elm;
 
-    if (root->refcount == 0)
-       return;
-    root->refcount--;
-    if (root->refcount == 0)
-       for (needed = root->needed;  needed != NULL;  needed = needed->next)
-           if (needed->obj != NULL)
-               unref_dag(needed->obj);
+    assert(root->dag_inited);
+    STAILQ_FOREACH(elm, &root->dagmembers, link)
+       elm->obj->refcount--;
 }
 
 /*
  * Common code for MD __tls_get_addr().
  */
 void *
-tls_get_addr_common(void **dtvp, int index, size_t offset)
+tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset)
 {
     Elf_Addr* dtv = *dtvp;
+    RtldLockState lockstate;
 
     /* Check dtv generation in case new modules have arrived */
     if (dtv[0] != tls_dtv_generation) {
        Elf_Addr* newdtv;
        int to_copy;
 
-       wlock_acquire();
-
+       wlock_acquire(rtld_bind_lock, &lockstate);
        newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr));
        to_copy = dtv[1];
        if (to_copy > tls_max_index)
@@ -2698,22 +3265,17 @@ tls_get_addr_common(void **dtvp, int index, size_t offset)
        newdtv[0] = tls_dtv_generation;
        newdtv[1] = tls_max_index;
        free(dtv);
+       lock_release(rtld_bind_lock, &lockstate);
        *dtvp = newdtv;
-
-       wlock_release();
     }
 
     /* Dynamically allocate module TLS if necessary */
     if (!dtv[index + 1]) {
-       /* XXX
-        * here we should avoid to be re-entered by signal handler
-        * code, I assume wlock_acquire will masked all signals,
-        * otherwise there is race and dead lock thread itself.
-        */
-       wlock_acquire();
-       if (!dtv[index + 1])
+       /* Signal safe, wlock will block out signals. */
+       wlock_acquire(rtld_bind_lock, &lockstate);
+       if (!dtv[index + 1])
            dtv[index + 1] = (Elf_Addr)allocate_module_tls(index);
-       wlock_release();
+       lock_release(rtld_bind_lock, &lockstate);
     }
     return (void*) (dtv[index + 1] + offset);
 }
@@ -2788,6 +3350,7 @@ free_tls(struct tls_tcb *tcb)
 
     data_size = (tls_static_space + RTLD_STATIC_TLS_ALIGN_MASK) &
                ~RTLD_STATIC_TLS_ALIGN_MASK;
+
     dtv = tcb->tcb_dtv;
     dtv_size = dtv[1];
     tls_end = (Elf_Addr)tcb;
@@ -2797,7 +3360,9 @@ free_tls(struct tls_tcb *tcb)
            free((void *)dtv[i+2]);
        }
     }
-    free((void *)tls_start);
+
+    free((void*) tls_start);
+    free((void*) dtv);
 }
 
 #else
@@ -2823,6 +3388,10 @@ allocate_module_tls(int index)
     }
 
     p = malloc(obj->tlssize);
+    if (p == NULL) {
+       _rtld_error("Cannot allocate TLS block for index %d", index);
+       die();
+    }
     memcpy(p, obj->tlsinit, obj->tlsinitsize);
     memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize);
 
@@ -2889,19 +3458,269 @@ struct tls_tcb *
 _rtld_allocate_tls(void)
 {
     struct tls_tcb *new_tcb;
+    RtldLockState lockstate;
 
-    wlock_acquire();
+    wlock_acquire(rtld_bind_lock, &lockstate);
     new_tcb = allocate_tls(obj_list);
-    wlock_release();
-
+    lock_release(rtld_bind_lock, &lockstate);
     return (new_tcb);
 }
 
 void
 _rtld_free_tls(struct tls_tcb *tcb)
 {
-    wlock_acquire();
+    RtldLockState lockstate;
+
+    wlock_acquire(rtld_bind_lock, &lockstate);
     free_tls(tcb);
-    wlock_release();
+    lock_release(rtld_bind_lock, &lockstate);
+}
+
+static void
+object_add_name(Obj_Entry *obj, const char *name)
+{
+    Name_Entry *entry;
+    size_t len;
+
+    len = strlen(name);
+    entry = malloc(sizeof(Name_Entry) + len);
+
+    if (entry != NULL) {
+       strcpy(entry->name, name);
+       STAILQ_INSERT_TAIL(&obj->names, entry, link);
+    }
+}
+
+static int
+object_match_name(const Obj_Entry *obj, const char *name)
+{
+    Name_Entry *entry;
+
+    STAILQ_FOREACH(entry, &obj->names, link) {
+       if (strcmp(name, entry->name) == 0)
+           return (1);
+    }
+    return (0);
+}
+
+static Obj_Entry *
+locate_dependency(const Obj_Entry *obj, const char *name)
+{
+    const Objlist_Entry *entry;
+    const Needed_Entry *needed;
+
+    STAILQ_FOREACH(entry, &list_main, link) {
+       if (object_match_name(entry->obj, name))
+           return entry->obj;
+    }
+
+    for (needed = obj->needed;  needed != NULL;  needed = needed->next) {
+       if (strcmp(obj->strtab + needed->name, name) == 0 ||
+         (needed->obj != NULL && object_match_name(needed->obj, name))) {
+           /*
+            * If there is DT_NEEDED for the name we are looking for,
+            * we are all set.  Note that object might not be found if
+            * dependency was not loaded yet, so the function can
+            * return NULL here.  This is expected and handled
+            * properly by the caller.
+            */
+           return (needed->obj);
+       }
+    }
+    _rtld_error("%s: Unexpected inconsistency: dependency %s not found",
+       obj->path, name);
+    die();
+}
+
+static int
+check_object_provided_version(Obj_Entry *refobj, const Obj_Entry *depobj,
+    const Elf_Vernaux *vna)
+{
+    const Elf_Verdef *vd;
+    const char *vername;
+
+    vername = refobj->strtab + vna->vna_name;
+    vd = depobj->verdef;
+    if (vd == NULL) {
+       _rtld_error("%s: version %s required by %s not defined",
+           depobj->path, vername, refobj->path);
+       return (-1);
+    }
+    for (;;) {
+       if (vd->vd_version != VER_DEF_CURRENT) {
+           _rtld_error("%s: Unsupported version %d of Elf_Verdef entry",
+               depobj->path, vd->vd_version);
+           return (-1);
+       }
+       if (vna->vna_hash == vd->vd_hash) {
+           const Elf_Verdaux *aux = (const Elf_Verdaux *)
+               ((char *)vd + vd->vd_aux);
+           if (strcmp(vername, depobj->strtab + aux->vda_name) == 0)
+               return (0);
+       }
+       if (vd->vd_next == 0)
+           break;
+       vd = (const Elf_Verdef *) ((char *)vd + vd->vd_next);
+    }
+    if (vna->vna_flags & VER_FLG_WEAK)
+       return (0);
+    _rtld_error("%s: version %s required by %s not found",
+       depobj->path, vername, refobj->path);
+    return (-1);
 }
 
+static int
+rtld_verify_object_versions(Obj_Entry *obj)
+{
+    const Elf_Verneed *vn;
+    const Elf_Verdef  *vd;
+    const Elf_Verdaux *vda;
+    const Elf_Vernaux *vna;
+    const Obj_Entry *depobj;
+    int maxvernum, vernum;
+
+    maxvernum = 0;
+    /*
+     * Walk over defined and required version records and figure out
+     * max index used by any of them. Do very basic sanity checking
+     * while there.
+     */
+    vn = obj->verneed;
+    while (vn != NULL) {
+       if (vn->vn_version != VER_NEED_CURRENT) {
+           _rtld_error("%s: Unsupported version %d of Elf_Verneed entry",
+               obj->path, vn->vn_version);
+           return (-1);
+       }
+       vna = (const Elf_Vernaux *) ((char *)vn + vn->vn_aux);
+       for (;;) {
+           vernum = VER_NEED_IDX(vna->vna_other);
+           if (vernum > maxvernum)
+               maxvernum = vernum;
+           if (vna->vna_next == 0)
+                break;
+           vna = (const Elf_Vernaux *) ((char *)vna + vna->vna_next);
+       }
+       if (vn->vn_next == 0)
+           break;
+       vn = (const Elf_Verneed *) ((char *)vn + vn->vn_next);
+    }
+
+    vd = obj->verdef;
+    while (vd != NULL) {
+       if (vd->vd_version != VER_DEF_CURRENT) {
+           _rtld_error("%s: Unsupported version %d of Elf_Verdef entry",
+               obj->path, vd->vd_version);
+           return (-1);
+       }
+       vernum = VER_DEF_IDX(vd->vd_ndx);
+       if (vernum > maxvernum)
+               maxvernum = vernum;
+       if (vd->vd_next == 0)
+           break;
+       vd = (const Elf_Verdef *) ((char *)vd + vd->vd_next);
+    }
+
+    if (maxvernum == 0)
+       return (0);
+
+    /*
+     * Store version information in array indexable by version index.
+     * Verify that object version requirements are satisfied along the
+     * way.
+     */
+    obj->vernum = maxvernum + 1;
+    obj->vertab = calloc(obj->vernum, sizeof(Ver_Entry));
+
+    vd = obj->verdef;
+    while (vd != NULL) {
+       if ((vd->vd_flags & VER_FLG_BASE) == 0) {
+           vernum = VER_DEF_IDX(vd->vd_ndx);
+           assert(vernum <= maxvernum);
+           vda = (const Elf_Verdaux *)((char *)vd + vd->vd_aux);
+           obj->vertab[vernum].hash = vd->vd_hash;
+           obj->vertab[vernum].name = obj->strtab + vda->vda_name;
+           obj->vertab[vernum].file = NULL;
+           obj->vertab[vernum].flags = 0;
+       }
+       if (vd->vd_next == 0)
+           break;
+       vd = (const Elf_Verdef *) ((char *)vd + vd->vd_next);
+    }
+
+    vn = obj->verneed;
+    while (vn != NULL) {
+       depobj = locate_dependency(obj, obj->strtab + vn->vn_file);
+       if (depobj == NULL)
+           return (-1);
+       vna = (const Elf_Vernaux *) ((char *)vn + vn->vn_aux);
+       for (;;) {
+           if (check_object_provided_version(obj, depobj, vna))
+               return (-1);
+           vernum = VER_NEED_IDX(vna->vna_other);
+           assert(vernum <= maxvernum);
+           obj->vertab[vernum].hash = vna->vna_hash;
+           obj->vertab[vernum].name = obj->strtab + vna->vna_name;
+           obj->vertab[vernum].file = obj->strtab + vn->vn_file;
+           obj->vertab[vernum].flags = (vna->vna_other & VER_NEED_HIDDEN) ?
+               VER_INFO_HIDDEN : 0;
+           if (vna->vna_next == 0)
+                break;
+           vna = (const Elf_Vernaux *) ((char *)vna + vna->vna_next);
+       }
+       if (vn->vn_next == 0)
+           break;
+       vn = (const Elf_Verneed *) ((char *)vn + vn->vn_next);
+    }
+    return 0;
+}
+
+static int
+rtld_verify_versions(const Objlist *objlist)
+{
+    Objlist_Entry *entry;
+    int rc;
+
+    rc = 0;
+    STAILQ_FOREACH(entry, objlist, link) {
+       /*
+        * Skip dummy objects or objects that have their version requirements
+        * already checked.
+        */
+       if (entry->obj->strtab == NULL || entry->obj->vertab != NULL)
+           continue;
+       if (rtld_verify_object_versions(entry->obj) == -1) {
+           rc = -1;
+           if (ld_tracing == NULL)
+               break;
+       }
+    }
+    if (rc == 0 || ld_tracing != NULL)
+       rc = rtld_verify_object_versions(&obj_rtld);
+    return rc;
+}
+
+const Ver_Entry *
+fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
+{
+    Elf_Versym vernum;
+
+    if (obj->vertab) {
+       vernum = VER_NDX(obj->versyms[symnum]);
+       if (vernum >= obj->vernum) {
+           _rtld_error("%s: symbol %s has wrong verneed value %d",
+               obj->path, obj->strtab + symnum, vernum);
+       } else if (obj->vertab[vernum].hash != 0) {
+           return &obj->vertab[vernum];
+       }
+    }
+    return NULL;
+}
+
+/*
+ * No unresolved symbols for rtld.
+ */
+void
+__pthread_cxa_finalize(struct dl_phdr_info *a)
+{
+}
index 631b898..c463b68 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/rtld.h,v 1.15.2.6 2003/02/20 20:42:46 kan Exp $
+ * $FreeBSD: src/libexec/rtld-elf/rtld.h,v 1.50 2011/02/09 09:20:27 kib Exp $
  */
 
 #ifndef RTLD_H /* { */
 
 #include <elf-hints.h>
 #include <link.h>
+#include <setjmp.h>
 #include <stddef.h>
 
+#include "rtld_lock.h"
 #include "rtld_machdep.h"
 
 #ifndef STANDARD_LIBRARY_PATH
@@ -77,6 +79,11 @@ typedef struct Struct_Needed_Entry {
     unsigned long name;                /* Offset of name in string table */
 } Needed_Entry;
 
+typedef struct Struct_Name_Entry {
+    STAILQ_ENTRY(Struct_Name_Entry) link;
+    char   name[1];
+} Name_Entry;
+
 /* Lock object */
 typedef struct Struct_LockInfo {
     void *context;             /* Client context for creating locks */
@@ -94,6 +101,15 @@ typedef struct Struct_LockInfo {
     void (*context_destroy)(void *context);
 } LockInfo;
 
+typedef struct Struct_Ver_Entry {
+       Elf_Word     hash;
+       unsigned int flags;
+       const char  *name;
+       const char  *file;
+} Ver_Entry;
+
+#define VER_INFO_HIDDEN        0x01
+
 /*
  * Shared object descriptor.
  *
@@ -152,28 +168,47 @@ typedef struct Struct_Obj_Entry {
     const char *strtab;                /* String table */
     unsigned long strsize;     /* Size in bytes of string table */
 
+    const Elf_Verneed *verneed; /* Required versions. */
+    Elf_Word verneednum;       /* Number of entries in verneed table */
+    const Elf_Verdef  *verdef; /* Provided versions. */
+    Elf_Word verdefnum;                /* Number of entries in verdef table */
+    const Elf_Versym *versyms;  /* Symbol versions table */
+
     const Elf_Hashelt *buckets;        /* Hash table buckets array */
     unsigned long nbuckets;    /* Number of buckets */
     const Elf_Hashelt *chains; /* Hash table chain array */
     unsigned long nchains;     /* Number of chains */
 
-    const char *rpath;         /* Search path specified in object */
+    char *rpath;               /* Search path specified in object */
     Needed_Entry *needed;      /* Shared objects needed by this one (%) */
 
-    InitFunc init;             /* Initialization function to call */
-    InitFunc fini;             /* Termination function to call */
-
-    bool mainprog;             /* True if this is the main program */
-    bool rtld;                 /* True if this is the dynamic linker */
-    bool textrel;              /* True if there are relocations to text seg */
-    bool symbolic;             /* True if generated with "-Bsymbolic" */
-    bool bind_now;             /* True if all relocations should be made first */
-    bool traced;               /* Already printed in ldd trace output */
-    bool jmpslots_done;                /* Already have relocated the jump slots */
-    bool init_done;            /* Already have added object to init list */
-    bool tls_done;             /* Already allocated offset for static TLS */
-
-    struct link_map linkmap;   /* for GDB and dlinfo() */
+    STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we
+                                              know about. */
+    Ver_Entry *vertab;         /* Versions required /defined by this object */
+    int vernum;                        /* Number of entries in vertab */
+
+    Elf_Addr init;             /* Initialization function to call */
+    Elf_Addr fini;             /* Termination function to call */
+
+    bool mainprog : 1;         /* True if this is the main program */
+    bool rtld : 1;             /* True if this is the dynamic linker */
+    bool textrel : 1;          /* True if there are relocations to text seg */
+    bool symbolic : 1;         /* True if generated with "-Bsymbolic" */
+    bool bind_now : 1;         /* True if all relocations should be made first */
+    bool traced : 1;           /* Already printed in ldd trace output */
+    bool jmpslots_done : 1;    /* Already have relocated the jump slots */
+    bool init_done : 1;                /* Already have added object to init list */
+    bool tls_done : 1;         /* Already allocated offset for static TLS */
+    bool phdr_alloc : 1;       /* Phdr is allocated and needs to be freed. */
+    bool z_origin : 1;         /* Process rpath and soname tokens */
+    bool z_nodelete : 1;       /* Do not unload the object and dependencies */
+    bool z_noopen : 1;         /* Do not load on dlopen */
+    bool ref_nodel : 1;                /* Refcount increased to prevent dlclose */
+    bool init_scanned: 1;      /* Object is already on init list. */
+    bool on_fini_list: 1;      /* Object is already on fini list. */
+    bool dag_inited : 1;       /* Object has its DAG initialized. */
+
+    struct link_map linkmap;   /* For GDB and dlinfo() */
     Objlist dldags;            /* Object belongs to these dlopened DAGs (%) */
     Objlist dagmembers;                /* DAG has these members (%) */
     dev_t dev;                 /* Object's filesystem's device */
@@ -184,6 +219,17 @@ typedef struct Struct_Obj_Entry {
 #define RTLD_MAGIC     0xd550b87a
 #define RTLD_VERSION   1
 
+/* Flags to be passed into symlook_ family of functions. */
+#define SYMLOOK_IN_PLT 0x01    /* Lookup for PLT symbol */
+#define SYMLOOK_DLSYM  0x02    /* Return newes versioned symbol. Used by
+                                  dlsym. */
+
+/* Flags for load_object(). */
+#define        RTLD_LO_NOLOAD  0x01    /* dlopen() specified RTLD_NOLOAD. */
+#define        RTLD_LO_DLOPEN  0x02    /* Load_object() called from dlopen(). */
+#define        RTLD_LO_TRACE           0x04    /* Only tracing. */
+#define        RTLD_LO_NODELETE        0x08    /* Loaded object cannot be closed. */
+
 /*
  * Symbol cache entry used during relocation to avoid multiple lookups
  * of the same symbol.
@@ -193,46 +239,53 @@ typedef struct Struct_SymCache {
     const Obj_Entry *obj;      /* Shared object which defines it */
 } SymCache;
 
-void            _rtld_error(const char *, ...) __printflike(1, 2);
-Obj_Entry      *map_object(int, const char *, const struct stat *);
-void           *xcalloc(size_t);
-void           *xmalloc(size_t);
-void           *xrealloc(void *, size_t);
-char           *xstrdup(const char *);
-
-void            dump_relocations(Obj_Entry *);
-void            dump_obj_relocations(Obj_Entry *);
-void            dump_Elf_Rel(Obj_Entry *, const Elf_Rel *, u_long);
-void            dump_Elf_Rela(Obj_Entry *, const Elf_Rela *, u_long);
-
+struct Struct_RtldLockState {
+       int lockstate;
+       sigjmp_buf env;
+};
+
+void _rtld_error(const char *, ...) __printflike(1, 2);
+Obj_Entry *map_object(int, const char *, const struct stat *);
+void *xcalloc(size_t);
+void *xmalloc(size_t);
+char *xstrdup(const char *);
+void *xrealloc(void *, size_t);
 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
 
+void dump_relocations(Obj_Entry *);
+void dump_obj_relocations(Obj_Entry *);
+void dump_Elf_Rel(Obj_Entry *, const Elf_Rel *, u_long);
+void dump_Elf_Rela(Obj_Entry *, const Elf_Rela *, u_long);
+
 /*
  * Function declarations.
  */
-const char     *basename(const char *);
-int             do_copy_relocations(Obj_Entry *);
-
-unsigned long   elf_hash(const char *);
-const Elf_Sym   *find_symdef(unsigned long, const Obj_Entry *,
-                             const Obj_Entry **, bool, SymCache *);
-void            init_pltgot(Obj_Entry *);
-void            lockdflt_init(LockInfo *);
-void            obj_free(Obj_Entry *);
-Obj_Entry      *obj_new(void);
-int             reloc_non_plt(Obj_Entry *, Obj_Entry *);
-int             reloc_plt(Obj_Entry *);
-int             reloc_jmpslots(Obj_Entry *);
-void            _rtld_bind_start(void);
+const char *basename(const char *);
+unsigned long elf_hash(const char *);
+const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
+  const Obj_Entry **, int, SymCache *);
+void init_pltgot(Obj_Entry *);
+void lockdflt_init(void);
+void obj_free(Obj_Entry *);
+Obj_Entry *obj_new(void);
+void _rtld_bind_start(void);
 const Elf_Sym  *symlook_obj(const char *, unsigned long, const Obj_Entry *,
-                            bool);
-
-void           *tls_get_addr_common(void **, int, size_t);
+  const Ver_Entry *, int);
+void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset);
 struct tls_tcb *allocate_tls(Obj_Entry *);
-void            free_tls(struct tls_tcb *);
-void            *allocate_module_tls(int);
-bool            allocate_tls_offset(Obj_Entry *);
-void            free_tls_offset(Obj_Entry *);
-void            allocate_initial_tls(Obj_Entry *);
+void free_tls(struct tls_tcb *);
+void *allocate_module_tls(int index);
+bool allocate_tls_offset(Obj_Entry *obj);
+void free_tls_offset(Obj_Entry *obj);
+const Ver_Entry *fetch_ventry(const Obj_Entry *obj, unsigned long);
+
+/*
+ * MD function declarations.
+ */
+int do_copy_relocations(Obj_Entry *);
+int reloc_non_plt(Obj_Entry *, Obj_Entry *);
+int reloc_plt(Obj_Entry *);
+int reloc_jmpslots(Obj_Entry *);
+void allocate_initial_tls(Obj_Entry *);
 
 #endif /* } */
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c
new file mode 100644 (file)
index 0000000..7d1c25d
--- /dev/null
@@ -0,0 +1,363 @@
+/*-
+ * Copyright 1999, 2000 John D. Polstra.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ *     from: FreeBSD: src/libexec/rtld-elf/sparc64/lockdflt.c,v 1.3 2002/10/09
+ * $FreeBSD: src/libexec/rtld-elf/rtld_lock.c,v 1.11 2011/02/09 09:20:27 kib Exp $
+ */
+
+/*
+ * Thread locking implementation for the dynamic linker.
+ *
+ * We use the "simple, non-scalable reader-preference lock" from:
+ *
+ *   J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
+ *   Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
+ *   Principles and Practice of Parallel Programming, April 1991.
+ *
+ * In this algorithm the lock is a single word.  Its low-order bit is
+ * set when a writer holds the lock.  The remaining high-order bits
+ * contain a count of readers desiring the lock.  The algorithm requires
+ * atomic "compare_and_store" and "add" operations, which we implement
+ * using assembly language sequences in "rtld_start.S".
+ */
+
+#include <sys/param.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "debug.h"
+#include "rtld.h"
+#include "rtld_machdep.h"
+
+#define WAFLAG         0x1     /* A writer holds the lock */
+#define RC_INCR                0x2     /* Adjusts count of readers desiring lock */
+
+typedef struct Struct_Lock {
+       volatile u_int lock;
+       void *base;
+} Lock;
+
+static sigset_t fullsigmask, oldsigmask;
+static int thread_flag;
+
+static void *
+def_lock_create()
+{
+    void *base;
+    char *p;
+    uintptr_t r;
+    Lock *l;
+
+    /*
+     * Arrange for the lock to occupy its own cache line.  First, we
+     * optimistically allocate just a cache line, hoping that malloc
+     * will give us a well-aligned block of memory.  If that doesn't
+     * work, we allocate a larger block and take a well-aligned cache
+     * line from it.
+     */
+    base = xmalloc(CACHE_LINE_SIZE);
+    p = (char *)base;
+    if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+       free(base);
+       base = xmalloc(2 * CACHE_LINE_SIZE);
+       p = (char *)base;
+       if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+           p += CACHE_LINE_SIZE - r;
+    }
+    l = (Lock *)p;
+    l->base = base;
+    l->lock = 0;
+    return l;
+}
+
+static void
+def_lock_destroy(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    free(l->base);
+}
+
+static void
+def_rlock_acquire(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    atomic_add_acq_int(&l->lock, RC_INCR);
+    while (l->lock & WAFLAG)
+           ;   /* Spin */
+}
+
+static void
+def_wlock_acquire(void *lock)
+{
+    Lock *l = (Lock *)lock;
+    sigset_t tmp_oldsigmask;
+
+    for ( ; ; ) {
+       sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+       if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
+           break;
+       sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
+    }
+    oldsigmask = tmp_oldsigmask;
+}
+
+static void
+def_lock_release(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    if ((l->lock & WAFLAG) == 0)
+       atomic_add_rel_int(&l->lock, -RC_INCR);
+    else {
+       atomic_add_rel_int(&l->lock, -WAFLAG);
+       sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
+    }
+}
+
+static int
+def_thread_set_flag(int mask)
+{
+       int old_val = thread_flag;
+       thread_flag |= mask;
+       return (old_val);
+}
+
+static int
+def_thread_clr_flag(int mask)
+{
+       int old_val = thread_flag;
+       thread_flag &= ~mask;
+       return (old_val);
+}
+
+/*
+ * Public interface exposed to the rest of the dynamic linker.
+ */
+static struct RtldLockInfo lockinfo;
+static struct RtldLockInfo deflockinfo;
+
+static __inline int
+thread_mask_set(int mask)
+{
+       return lockinfo.thread_set_flag(mask);
+}
+
+static __inline void
+thread_mask_clear(int mask)
+{
+       lockinfo.thread_clr_flag(mask);
+}
+
+#define        RTLD_LOCK_CNT   3
+struct rtld_lock {
+       void    *handle;
+       int      mask;
+} rtld_locks[RTLD_LOCK_CNT];
+
+rtld_lock_t    rtld_bind_lock = &rtld_locks[0];
+rtld_lock_t    rtld_libc_lock = &rtld_locks[1];
+rtld_lock_t    rtld_phdr_lock = &rtld_locks[2];
+
+#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0)
+
+void
+rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
+{
+
+       if (lockstate == NULL)
+               return;
+
+       if (thread_mask_set(lock->mask) & lock->mask) {
+               dbg("rlock_acquire: recursed");
+               lockstate->lockstate = RTLD_LOCK_UNLOCKED;
+               return;
+       }
+       lockinfo.rlock_acquire(lock->handle);
+       lockstate->lockstate = RTLD_LOCK_RLOCKED;
+}
+
+void
+wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
+{
+
+       if (lockstate == NULL)
+               return;
+
+       if (thread_mask_set(lock->mask) & lock->mask) {
+               dbg("wlock_acquire: recursed");
+               lockstate->lockstate = RTLD_LOCK_UNLOCKED;
+               return;
+       }
+       lockinfo.wlock_acquire(lock->handle);
+       lockstate->lockstate = RTLD_LOCK_WLOCKED;
+}
+
+void
+lock_release(rtld_lock_t lock, RtldLockState *lockstate)
+{
+
+       if (lockstate == NULL)
+               return;
+
+       switch (lockstate->lockstate) {
+       case RTLD_LOCK_UNLOCKED:
+               break;
+       case RTLD_LOCK_RLOCKED:
+       case RTLD_LOCK_WLOCKED:
+               thread_mask_clear(lock->mask);
+               lockinfo.lock_release(lock->handle);
+               break;
+       default:
+               assert(0);
+       }
+}
+
+void
+lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate)
+{
+
+       if (lockstate == NULL)
+               return;
+
+       lock_release(lock, lockstate);
+       wlock_acquire(lock, lockstate);
+}
+
+void
+lock_restart_for_upgrade(RtldLockState *lockstate)
+{
+
+       if (lockstate == NULL)
+               return;
+
+       switch (lockstate->lockstate) {
+       case RTLD_LOCK_UNLOCKED:
+       case RTLD_LOCK_WLOCKED:
+               break;
+       case RTLD_LOCK_RLOCKED:
+               siglongjmp(lockstate->env, 1);
+               break;
+       default:
+               assert(0);
+       }
+}
+
+void
+lockdflt_init()
+{
+    int i;
+
+    deflockinfo.rtli_version  = RTLI_VERSION;
+    deflockinfo.lock_create   = def_lock_create;
+    deflockinfo.lock_destroy  = def_lock_destroy;
+    deflockinfo.rlock_acquire = def_rlock_acquire;
+    deflockinfo.wlock_acquire = def_wlock_acquire;
+    deflockinfo.lock_release  = def_lock_release;
+    deflockinfo.thread_set_flag = def_thread_set_flag;
+    deflockinfo.thread_clr_flag = def_thread_clr_flag;
+    deflockinfo.at_fork = NULL;
+
+    for (i = 0; i < RTLD_LOCK_CNT; i++) {
+           rtld_locks[i].mask   = (1 << i);
+           rtld_locks[i].handle = NULL;
+    }
+
+    memcpy(&lockinfo, &deflockinfo, sizeof(lockinfo));
+    _rtld_thread_init(NULL);
+    /*
+     * Construct a mask to block all signals except traps which might
+     * conceivably be generated within the dynamic linker itself.
+     */
+    sigfillset(&fullsigmask);
+    sigdelset(&fullsigmask, SIGILL);
+    sigdelset(&fullsigmask, SIGTRAP);
+    sigdelset(&fullsigmask, SIGABRT);
+    sigdelset(&fullsigmask, SIGEMT);
+    sigdelset(&fullsigmask, SIGFPE);
+    sigdelset(&fullsigmask, SIGBUS);
+    sigdelset(&fullsigmask, SIGSEGV);
+    sigdelset(&fullsigmask, SIGSYS);
+}
+
+/*
+ * Callback function to allow threads implementation to
+ * register their own locking primitives if the default
+ * one is not suitable.
+ * The current context should be the only context
+ * executing at the invocation time.
+ */
+void
+_rtld_thread_init(struct RtldLockInfo *pli)
+{
+       int flags, i;
+       void *locks[RTLD_LOCK_CNT];
+
+       /* disable all locking while this function is running */
+       flags = thread_mask_set(~0);
+
+       if (pli == NULL)
+               pli = &deflockinfo;
+
+
+       for (i = 0; i < RTLD_LOCK_CNT; i++)
+               if ((locks[i] = pli->lock_create()) == NULL)
+                       break;
+
+       if (i < RTLD_LOCK_CNT) {
+               while (--i >= 0)
+                       pli->lock_destroy(locks[i]);
+               abort();
+       }
+
+       for (i = 0; i < RTLD_LOCK_CNT; i++) {
+               if (rtld_locks[i].handle == NULL)
+                       continue;
+               if (flags & rtld_locks[i].mask)
+                       lockinfo.lock_release(rtld_locks[i].handle);
+               lockinfo.lock_destroy(rtld_locks[i].handle);
+       }
+
+       for (i = 0; i < RTLD_LOCK_CNT; i++) {
+               rtld_locks[i].handle = locks[i];
+               if (flags & rtld_locks[i].mask)
+                       pli->wlock_acquire(rtld_locks[i].handle);
+       }
+
+       lockinfo.lock_create = pli->lock_create;
+       lockinfo.lock_destroy = pli->lock_destroy;
+       lockinfo.rlock_acquire = pli->rlock_acquire;
+       lockinfo.wlock_acquire = pli->wlock_acquire;
+       lockinfo.lock_release  = pli->lock_release;
+       lockinfo.thread_set_flag = pli->thread_set_flag;
+       lockinfo.thread_clr_flag = pli->thread_clr_flag;
+       lockinfo.at_fork = pli->at_fork;
+
+       /* restore thread locking state, this time with new locks */
+       thread_mask_clear(~0);
+       thread_mask_set(flags);
+       dbg("_rtld_thread_init: done");
+}
similarity index 52%
copy from libexec/rtld-elf/debug.h
copy to libexec/rtld-elf/rtld_lock.h
index f02214e..329bb84 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright 1996-1998 John D. Polstra.
+ * Copyright 2003 Alexander Kabaev.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/debug.h,v 1.4 1999/12/27 04:44:01 jdp Exp $
- * $DragonFly: src/libexec/rtld-elf/debug.h,v 1.3 2005/05/11 19:47:06 dillon Exp $
+ * $FreeBSD: src/libexec/rtld-elf/rtld_lock.h,v 1.6 2010/12/25 08:51:20 kib Exp $
  */
 
-/*
- * Support for printing debugging messages.
- */
+#ifndef _RTLD_LOCK_H_
+#define        _RTLD_LOCK_H_
 
-#ifndef DEBUG_H
-#define DEBUG_H 1
+#define        RTLI_VERSION    0x01
 
-#ifndef __GNUC__
-#error "This file must be compiled with GCC"
-#endif
+struct RtldLockInfo
+{
+       unsigned int rtli_version;
+       void *(*lock_create)(void);
+       void  (*lock_destroy)(void *);
+       void  (*rlock_acquire)(void *);
+       void  (*wlock_acquire)(void *);
+       void  (*lock_release)(void *);
+       int   (*thread_set_flag)(int);
+       int   (*thread_clr_flag)(int);
+       void  (*at_fork)(void);
+};
 
-#include <sys/cdefs.h>
+extern void _rtld_thread_init(struct RtldLockInfo *);
 
-#include <string.h>
-#include <unistd.h>
+#ifdef IN_RTLD
 
-extern void debug_printf(const char *, ...) __printflike(1, 2);
-extern int debug;
+struct rtld_lock;
+typedef struct rtld_lock *rtld_lock_t;
 
-#ifdef DEBUG
-#define dbg(format, args...)   debug_printf(format , ## args)
-#else
-#define dbg(format, args...)   ((void) 0)
-#endif
+extern rtld_lock_t     rtld_bind_lock;
+extern rtld_lock_t     rtld_libc_lock;
+extern rtld_lock_t     rtld_phdr_lock;
+
+#define        RTLD_LOCK_UNLOCKED      0
+#define        RTLD_LOCK_RLOCKED       1
+#define        RTLD_LOCK_WLOCKED       2
 
-#define assert(cond)   ((cond) ? (void) 0 :            \
-    (msg("ld-elf.so.2: assert failed: " __FILE__ ":"   \
-      __XSTRING(__LINE__) "\n"), abort()))
-#define msg(s)         write(1, s, strlen(s))
-#define trace()                msg("ld-elf.so.2: " __XSTRING(__LINE__) "\n")
+struct Struct_RtldLockState;
+typedef struct Struct_RtldLockState RtldLockState;
 
-#endif /* DEBUG_H */
+void   rlock_acquire(rtld_lock_t, RtldLockState *);
+void   wlock_acquire(rtld_lock_t, RtldLockState *);
+void   lock_release(rtld_lock_t, RtldLockState *);
+void   lock_upgrade(rtld_lock_t, RtldLockState *);
+void   lock_restart_for_upgrade(RtldLockState *);
+
+#endif /* IN_RTLD */
+
+#endif
diff --git a/libexec/rtld-elf/x86_64/lockdflt.c b/libexec/rtld-elf/x86_64/lockdflt.c
deleted file mode 100644 (file)
index 21bb8f4..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*-
- * Copyright 1999, 2000 John D. Polstra.
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- * $FreeBSD: src/libexec/rtld-elf/i386/lockdflt.c,v 1.5.2.4 2002/07/11 23:52:32 jdp Exp $
- */
-
-/*
- * Thread locking implementation for the dynamic linker.
- *
- *   J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
- *   Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
- *   Principles and Practice of Parallel Programming, April 1991.
- *
- * In this algorithm the lock is a single word.  Its low-order bit is
- * set when a writer holds the lock.  The remaining high-order bits
- * contain a count of readers desiring the lock.  The algorithm requires
- * atomic "compare_and_store" and "add" operations.
- */
-
-#include <setjmp.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "debug.h"
-#include "rtld.h"
-
-#define WAFLAG         0x1     /* A writer holds the lock */
-#define RC_INCR                0x2     /* Adjusts count of readers desiring lock */
-
-typedef struct Struct_Lock {
-       volatile int lock;
-       void *base;
-} Lock;
-
-static sigset_t fullsigmask, oldsigmask;
-
-static inline int
-cmpxchgl(int old, int new, volatile int *m)
-{
-       int result;
-
-       __asm __volatile ("lock; cmpxchgl %2, %0"
-           : "+m"(*m), "=a"(result)
-           : "r"(new), "1"(old)
-           : "cc");
-
-       return result;
-}
-
-static void *
-lock_create(void *context)
-{
-    void *base;
-    char *p;
-    uintptr_t r;
-    Lock *l;
-
-    /*
-     * Arrange for the lock to occupy its own cache line.  First, we
-     * optimistically allocate just a cache line, hoping that malloc
-     * will give us a well-aligned block of memory.  If that doesn't
-     * work, we allocate a larger block and take a well-aligned cache
-     * line from it.
-     */
-    base = xmalloc(CACHE_LINE_SIZE);
-    p = (char *)base;
-    if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
-       free(base);
-       base = xmalloc(2 * CACHE_LINE_SIZE);
-       p = (char *)base;
-       if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
-           p += CACHE_LINE_SIZE - r;
-    }
-    l = (Lock *)p;
-    l->base = base;
-    l->lock = 0;
-    return l;
-}
-
-static void
-lock_destroy(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    free(l->base);
-}
-
-/*
- * Better reader/writer locks for the 80486 and later CPUs.
- */
-static void
-rlock_acquire(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, RC_INCR);
-    while (l->lock & WAFLAG)
-           ;   /* Spin */
-}
-
-static void
-wlock_acquire(void *lock)
-{
-    Lock *l = (Lock *)lock;
-    sigset_t tmp_oldsigmask;
-
-    for ( ; ; ) {
-       sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
-       if (cmpxchgl(0, WAFLAG, &l->lock) == 0)
-           break;
-       sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
-    }
-    oldsigmask = tmp_oldsigmask;
-}
-
-static void
-rlock_release(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, -RC_INCR);
-}
-
-static void
-wlock_release(void *lock)
-{
-    Lock *l = (Lock *)lock;
-
-    atomic_add_int(&l->lock, -WAFLAG);
-    sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
-}
-
-void
-lockdflt_init(LockInfo *li)
-{
-    li->context = NULL;
-    li->context_destroy = NULL;
-    li->lock_create = lock_create;
-    li->lock_destroy = lock_destroy;
-    li->rlock_acquire = rlock_acquire;
-    li->wlock_acquire = wlock_acquire;
-    li->rlock_release = rlock_release;
-    li->wlock_release = wlock_release;
-    /*
-     * Construct a mask to block all signals except traps which might
-     * conceivably be generated within the dynamic linker itself.
-     */
-    sigfillset(&fullsigmask);
-    sigdelset(&fullsigmask, SIGILL);
-    sigdelset(&fullsigmask, SIGTRAP);
-    sigdelset(&fullsigmask, SIGABRT);
-    sigdelset(&fullsigmask, SIGEMT);
-    sigdelset(&fullsigmask, SIGFPE);
-    sigdelset(&fullsigmask, SIGBUS);
-    sigdelset(&fullsigmask, SIGSEGV);
-    sigdelset(&fullsigmask, SIGSYS);
-}
index 81ed53b..8a0a31b 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/amd64/reloc.c,v 1.18 2006/03/28 06:09:24 davidxu Exp $
+ * $FreeBSD: src/libexec/rtld-elf/amd64/reloc.c,v 1.20 2010/12/25 08:51:20 kib Exp $
  */
 
 /*
@@ -77,15 +77,17 @@ do_copy_relocations(Obj_Entry *dstobj)
            const void *srcaddr;
            const Elf_Sym *srcsym;
            Obj_Entry *srcobj;
+           const Ver_Entry *ve;
 
            dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
            dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
            name = dstobj->strtab + dstsym->st_name;
            hash = elf_hash(name);
            size = dstsym->st_size;
+           ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
 
            for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-               if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
+               if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
                    break;
 
            if (srcobj == NULL) {
@@ -119,15 +121,16 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
        const Elf_Rela *relalim;
        const Elf_Rela *rela;
        SymCache *cache;
-       int bytes = obj->nchains * sizeof(SymCache);
        int r = -1;
 
        /*
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
-       cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-       if (cache == MAP_FAILED)
+       if (obj != obj_rtld) {
+           cache = calloc(obj->nchains, sizeof(SymCache));
+           /* No need to check for NULL here */
+       } else
            cache = NULL;
 
        relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
@@ -323,8 +326,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
        }
        r = 0;
 done:
-       if (cache)
-           munmap(cache, bytes);
+       if (cache != NULL)
+           free(cache);
        return(r);
 }
 
@@ -369,7 +372,7 @@ reloc_jmpslots(Obj_Entry *obj)
        if (def == NULL)
            return -1;
        target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
-       reloc_jmpslot(where, target);
+       reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
     }
     obj->jmpslots_done = true;
     return 0;
@@ -378,13 +381,18 @@ reloc_jmpslots(Obj_Entry *obj)
 void *__tls_get_addr(tls_index *ti)
 {
     struct tls_tcb *tcb;
+    Elf_Addr* dtv;
 
     tcb = tls_get_tcb();
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    dtv = (Elf_Addr*)tcb->tcb_dtv;
+
+    return tls_get_addr_common(&dtv, ti->ti_module, ti->ti_offset);
 }
 
 void *
 __tls_get_addr_tcb(struct tls_tcb *tcb, tls_index *ti)
 {
-    return tls_get_addr_common(&tcb->tcb_dtv, ti->ti_module, ti->ti_offset);
+    Elf_Addr* dtv = (Elf_Addr*)tcb->tcb_dtv;
+
+    return tls_get_addr_common(&dtv, ti->ti_module, ti->ti_offset);
 }
index 308178f..da2763a 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/amd64/rtld_machdep.h,v 1.13 2006/03/29 12:29:01 des Exp $
+ * $FreeBSD: src/libexec/rtld-elf/amd64/rtld_machdep.h,v 1.15 2011/01/25 21:12:31 kib Exp $
  */
 
 #ifndef RTLD_MACHDEP_H
@@ -42,7 +42,9 @@ struct Struct_Obj_Entry;
 
 /* Fixup the jump slot at "where" to transfer control to "target". */
 static inline Elf_Addr
-reloc_jmpslot(Elf_Addr *where, Elf_Addr target)
+reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
+             const struct Struct_Obj_Entry *obj,
+             const struct Struct_Obj_Entry *refobj, const Elf_Rel *rel)
 {
 #ifdef dbg
     dbg("reloc_jmpslot: *%p = %p", (void *)(where),
@@ -52,18 +54,6 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target)
     return target;
 }
 
-static inline void
-atomic_decr_int(volatile int *p)
-{
-    __asm __volatile ("lock; decl %0" : "+m"(*p) : : "cc");
-}
-
-static inline void
-atomic_incr_int(volatile int *p)
-{
-    __asm __volatile ("lock; incl %0" : "+m"(*p) : : "cc");
-}
-
 #define make_function_pointer(def, defobj) \
        ((defobj)->relocbase + (def)->st_value)
 
index 5e7c33f..8778900 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/libexec/rtld-elf/amd64/rtld_start.S,v 1.5 2004/03/21 01:43:39 peter Exp $
+ * $FreeBSD: src/libexec/rtld-elf/amd64/rtld_start.S,v 1.6 2011/01/07 16:07:05 kib Exp $
  */
 
 /*
@@ -95,6 +95,7 @@ _rtld_bind_start:
        pushq   %r9                     # Save %r9
        pushq   %r10                    # Save %r10
        pushq   %r11                    # Save %r11
+
        movq    0x58(%rsp),%rdi         # Fetch obj argument    (arg 1)
        movq    0x60(%rsp),%rsi         # Fetch reloff argument (arg 2)
        leaq    0x68(%rsp),%rdx         # Fetch original stack pointer (arg 3)
@@ -117,3 +118,5 @@ _rtld_bind_start:
        popfq                           # Restore rflags
        leaq    16(%rsp),%rsp           # Discard spare, obj, do not change rflags
        ret                             # "Return" to target address
+
+       .section .note.GNU-stack,"",%progbits
index 7475127..d384511 100644 (file)
@@ -1,6 +1,5 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/5/93
-#      $FreeBSD: src/share/man/man5/Makefile,v 1.27.2.12 2003/05/23 22:20:24 dwhite Exp $
-#      $DragonFly: src/share/man/man5/Makefile,v 1.18 2008/07/27 18:25:38 thomas Exp $
+#      $FreeBSD: src/share/man/man5/Makefile 211725 2010-08-23 22:24:11Z imp $
 
 #MISSING: dump.5 plot.5
 MAN=   acct.5 \
@@ -30,6 +29,7 @@ MAN=  acct.5 \
        hosts.equiv.5 \
        hosts.lpd.5 \
        intro.5 \
+       libmap.conf.5 \
        kernconf.5 \
        kernel.conf.5 \
        link.5 \
diff --git a/share/man/man5/libmap.conf.5 b/share/man/man5/libmap.conf.5
new file mode 100644 (file)
index 0000000..6d357ff
--- /dev/null
@@ -0,0 +1,155 @@
+.\" Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD: head/share/man/man5/libmap.conf.5 157178 2006-03-27 14:37:54Z pav $
+.\"
+.Dd February 20, 2011
+.Dt LIBMAP.CONF 5
+.Os
+.Sh NAME
+.Nm libmap.conf
+.Nd "configuration file for dynamic object dependency mapping"
+.Sh DESCRIPTION
+The
+.Nm libmap
+functionality of
+.Xr ld-elf.so.1 1
+allows dynamic object dependencies to be mapped to arbitrary
+names.
+.Pp
+The configuration file consists of two whitespace separated columns; the
+left hand side containing the mapping candidate and the right hand
+side containing the mapping.
+Dependencies are matched against candidates and replaced with the mappings.
+.Pp
+Constrained mappings may be specified by enclosing the name of the
+executable or library in brackets.
+All mappings following a constraint will only be evaluated for that constraint.
+Constraints can be one of three types:
+.Bl -tag -width indent
+.It Exact
+The constraint is matched literally so that only an executable with an
+identical fully qualified pathname will match the constraint.
+This means that the executable
+.Pa /usr/bin/foo
+will not match a constraint for
+.Pa /usr/bin/./foo
+and vice-versa.
+This is the default constraint type.
+.It Basename
+A constraint with no path is matched against the basename of the
+executable.
+.Pa foo
+will match
+.Pa /bin/foo ,
+.Pa /usr/local/sbin/foo ,
+or any other executable named
+.Pa foo ,
+no matter what its path is.
+.It Directory
+A constraint with a trailing slash is prefix-matched against the full
+pathname of the executable.
+.Pa /usr/bin/
+will match any executable with a path starting with /usr/bin.
+.El
+.Pp
+Note that the executable path matched against is the
+.Fa path
+parameter in an
+.Fn exec*
+function call.
+The Directory or Exact constraints can only match when the executable
+is called with a full pathname.
+Most programs executed from a shell are run without a full path, via
+.Fn exec*p ,
+so the Basename constraint type is the most useful.
+.Pp
+WARNING!
+Constrained mappings must never appear first in the configuration file.
+While there is a way to specify the
+.Dq default
+constraint, its use is not recommended.
+.Pp
+The most common use at the date of writing is for allowing multiple
+.Tn POSIX
+threading libraries to be used on a system without relinking or
+changing symlinks.
+.Pp
+This mechanism has also been used to create shims to allow Linux
+shared libraries to be dynamically loaded into
+.Fx
+binaries.
+In this case, an Exact constraint is used for the Linux shared library,
+mapping libraries it depends on to a wrapper.
+The wrapper then defines any needed symbols for the Linux shared library
+and relies on its libraries not being mapped to provide actual
+implementations.
+It appears that only libraries loaded via
+.Xr dlopen 3
+will work correctly.
+The symbol version information in shared libraries is checked at
+link time, but at run time the version information is currently
+ignored.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/libmap.conf" -compact
+.It Pa /etc/libmap.conf
+The libmap configuration file.
+.El
+.Sh EXAMPLES
+.Bd -literal
+# /etc/libmap.conf
+#
+# candidate            mapping
+#
+libc_r.so.6            libpthread.so.2 # Everything that uses 'libc_r'
+libc_r.so              libpthread.so   # now uses 'libpthread'
+
+[/tmp/mplayer]         # Test version of mplayer uses libc_r
+libpthread.so.2                libc_r.so.6
+libpthread.so          libc_r.so
+
+[/usr/local/jdk1.4.1/] # All Java 1.4.1 programs use libthr
+                       # This works because "javavms" executes
+                       # programs with the full pathname
+libpthread.so.2                libthr.so.2
+libpthread.so          libthr.so
+
+# Glue for Linux-only EPSON printer .so to be loaded into cups, etc.
+[/usr/local/lib/pips/libsc80c.so]
+libc.so.6              pluginwrapper/pips.so
+libdl.so.2             pluginwrapper/pips.so
+.Ed
+.Sh SEE ALSO
+.Xr ldd 1 ,
+.Xr rtld 1
+.Sh HISTORY
+The
+.Nm
+manual page and
+.Nm libmap
+functionality first appeared in
+.Fx 5.1 .
+.Sh AUTHORS
+This manual page was written by
+.An Matthew N. Dodd Aq winter@jurai.net .
index ae950f3..3ffe40f 100644 (file)
@@ -23,8 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/i386/include/elf.h,v 1.9.2.1 2001/11/03 01:41:08 ps Exp $
- * $DragonFly: src/sys/cpu/i386/include/elf.h,v 1.8 2006/11/07 06:43:22 dillon Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.22 2011/01/07 14:22:34 kib Exp $
  */
 
 #ifndef _CPU_ELF_H_
@@ -73,16 +72,16 @@ typedef struct {
 __ElfType(Auxinfo);
 
 /* Values for a_type. */
-#define AT_NULL                0       /* Terminates the vector. */
-#define AT_IGNORE      1       /* Ignored entry. */
-#define AT_EXECFD      2       /* File descriptor of program to load. */
-#define AT_PHDR                3       /* Program header of program already loaded. */
-#define AT_PHENT       4       /* Size of each program header entry. */
-#define AT_PHNUM       5       /* Number of program header entries. */
-#define AT_PAGESZ      6       /* Page size in bytes. */
-#define AT_BASE                7       /* Interpreter's base address. */
-#define AT_FLAGS       8       /* Flags (unused for i386). */
-#define AT_ENTRY       9       /* Where interpreter should transfer control. */
+#define        AT_NULL         0       /* Terminates the vector. */
+#define        AT_IGNORE       1       /* Ignored entry. */
+#define        AT_EXECFD       2       /* File descriptor of program to load. */
+#define        AT_PHDR         3       /* Program header of program already loaded. */
+#define        AT_PHENT        4       /* Size of each program header entry. */
+#define        AT_PHNUM        5       /* Number of program header entries. */
+#define        AT_PAGESZ       6       /* Page size in bytes. */
+#define        AT_BASE         7       /* Interpreter's base address. */
+#define        AT_FLAGS        8       /* Flags (unused for i386). */
+#define        AT_ENTRY        9       /* Where interpreter should transfer control. */
 
 /*
  * The following non-standard values are used for passing information
@@ -92,19 +91,28 @@ __ElfType(Auxinfo);
  * Unfortunately, these overlap the Linux non-standard values, so they
  * must not be used in the same context.
  */
-#define AT_BRK         10      /* Starting point for sbrk and brk. */
-#define AT_DEBUG       11      /* Debugging level. */
+#define        AT_BRK          10      /* Starting point for sbrk and brk. */
+#define        AT_DEBUG        11      /* Debugging level. */
 
 /*
  * The following non-standard values are used in Linux ELF binaries.
+ * Types 16 - 23 are not implemented in the kernel
  */
-#define AT_NOTELF      10      /* Program is not ELF ?? */
-#define AT_UID         11      /* Real uid. */
-#define AT_EUID                12      /* Effective uid. */
-#define AT_GID         13      /* Real gid. */
-#define AT_EGID                14      /* Effective gid. */
-
-#define AT_COUNT       15      /* Count of defined aux entry types. */
+#define        AT_NOTELF       10      /* Program is not ELF ?? */
+#define        AT_UID          11      /* Real uid. */
+#define        AT_EUID         12      /* Effective uid. */
+#define        AT_GID          13      /* Real gid. */
+#define        AT_EGID         14      /* Effective gid. */
+#define        AT_EXECPATH     15      /* Path to the executable. */
+#define        AT_CANARY       16      /* Canary for SSP. */
+#define        AT_CANARYLEN    17      /* Length of the canary. */
+#define        AT_OSRELDATE    18      /* OSRELDATE. */
+#define        AT_NCPUS        19      /* Number of CPUs. */
+#define        AT_PAGESIZES    20      /* Pagesizes. */
+#define        AT_PAGESIZESLEN 21      /* Number of pagesizes. */
+#define        AT_STACKPROT    23      /* Initial stack protection. */
+
+#define        AT_COUNT        24      /* Count of defined aux entry types. */
 
 /*
  * Relocation types.
index f57d450..33d782f 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.25 2011/01/07 14:22:34 kib Exp $
  */
 
 #ifndef _CPU_ELF_H_
@@ -95,14 +95,23 @@ __ElfType(Auxinfo);
 
 /*
  * The following non-standard values are used in Linux ELF binaries.
+ * Types 16 - 23 are not implemented in the kernel
  */
 #define        AT_NOTELF       10      /* Program is not ELF ?? */
 #define        AT_UID          11      /* Real uid. */
 #define        AT_EUID         12      /* Effective uid. */
 #define        AT_GID          13      /* Real gid. */
 #define        AT_EGID         14      /* Effective gid. */
-
-#define        AT_COUNT        15      /* Count of defined aux entry types. */
+#define        AT_EXECPATH     15      /* Path to the executable. */
+#define        AT_CANARY       16      /* Canary for SSP */
+#define        AT_CANARYLEN    17      /* Length of the canary. */
+#define        AT_OSRELDATE    18      /* OSRELDATE. */
+#define        AT_NCPUS        19      /* Number of CPUs. */
+#define        AT_PAGESIZES    20      /* Pagesizes. */
+#define        AT_PAGESIZESLEN 21      /* Number of pagesizes. */
+#define        AT_STACKPROT    23      /* Initial stack protection. */
+
+#define        AT_COUNT        24      /* Count of defined aux entry types. */
 
 /*
  * Relocation types.
index 0efd10b..8f89193 100644 (file)
@@ -24,7 +24,6 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/sys/elf32.h,v 1.7 1999/08/28 00:51:41 peter Exp $
- * $DragonFly: src/sys/sys/elf32.h,v 1.5 2006/10/23 21:50:33 dillon Exp $
  */
 
 #ifndef _SYS_ELF32_H_
@@ -159,4 +158,50 @@ typedef struct {
 /* Macro for constructing st_info from field values. */
 #define ELF32_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
 
+/* Macro for accessing the fields of st_other. */
+#define ELF32_ST_VISIBILITY(oth)       ((oth) & 0x3)
+
+/* Structures used by Sun & GNU symbol versioning. */
+typedef struct
+{
+       Elf32_Half      vd_version;
+       Elf32_Half      vd_flags;
+       Elf32_Half      vd_ndx;
+       Elf32_Half      vd_cnt;
+       Elf32_Word      vd_hash;
+       Elf32_Word      vd_aux;
+       Elf32_Word      vd_next;
+} Elf32_Verdef;
+
+typedef struct
+{
+       Elf32_Word      vda_name;
+       Elf32_Word      vda_next;
+} Elf32_Verdaux;
+
+typedef struct
+{
+       Elf32_Half      vn_version;
+       Elf32_Half      vn_cnt;
+       Elf32_Word      vn_file;
+       Elf32_Word      vn_aux;
+       Elf32_Word      vn_next;
+} Elf32_Verneed;
+
+typedef struct
+{
+       Elf32_Word      vna_hash;
+       Elf32_Half      vna_flags;
+       Elf32_Half      vna_other;
+       Elf32_Word      vna_name;
+       Elf32_Word      vna_next;
+} Elf32_Vernaux;
+
+typedef Elf32_Half Elf32_Versym;
+
+typedef struct {
+       Elf32_Half      si_boundto;     /* direct bindings - symbol bound to */
+       Elf32_Half      si_flags;       /* per symbol flags */
+} Elf32_Syminfo;
+
 #endif /* !_SYS_ELF32_H_ */
index 5df5c9b..7c6eceb 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/sys/elf_common.h,v 1.5.2.3 2001/02/28 02:30:46 obrien Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.37 2010/11/23 12:51:08 kib Exp $
  */
 
 #ifndef _SYS_ELF_COMMON_H_
@@ -89,26 +89,28 @@ typedef struct {
 #define ELFDATA2MSB    2       /* 2's complement big-endian. */
 
 /* Values for e_ident[EI_OSABI]. */
-#define ELFOSABI_SYSV          0       /* UNIX System V ABI */
-#define ELFOSABI_NONE          ELFOSABI_SYSV   /* symbol used in old spec */
+#define ELFOSABI_NONE          0       /* UNIX System V ABI */
 #define ELFOSABI_HPUX          1       /* HP-UX operating system */
 #define ELFOSABI_NETBSD                2       /* NetBSD */
 #define ELFOSABI_LINUX         3       /* GNU/Linux */
 #define ELFOSABI_HURD          4       /* GNU/Hurd */
 #define ELFOSABI_86OPEN                5       /* 86Open common IA32 ABI */
 #define ELFOSABI_SOLARIS       6       /* Solaris */
-#define ELFOSABI_MONTEREY      7       /* Monterey */
+#define ELFOSABI_AIX           7       /* AIX */
 #define ELFOSABI_IRIX          8       /* IRIX */
 #define ELFOSABI_FREEBSD       9       /* FreeBSD */
 #define ELFOSABI_TRU64         10      /* TRU64 UNIX */
 #define ELFOSABI_MODESTO       11      /* Novell Modesto */
 #define ELFOSABI_OPENBSD       12      /* OpenBSD */
-#define ELFOSABI_OPENVMS       13      /* OpenVMS */
+#define ELFOSABI_OPENVMS       13      /* Open VMS */
 #define ELFOSABI_NSK           14      /* HP Non-Stop Kernel */
-#define ELSOSABI_AROS          15      /* Amiga Research OS */
+#define ELFOSABI_AROS          15      /* Amiga Research OS */
 #define ELFOSABI_ARM           97      /* ARM */
 #define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
 
+#define ELFOSABI_SYSV          ELFOSABI_NONE   /* symbol used in old spec */
+#define ELFOSABI_MONTEREY      ELFOSABI_AIX    /* Monterey */
+
 /* e_ident */
 #define IS_ELF(ehdr)   ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
                         (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
@@ -133,29 +135,22 @@ typedef struct {
 #define EM_386         3       /* Intel i386. */
 #define EM_68K         4       /* Motorola 68000. */
 #define EM_88K         5       /* Motorola 88000. */
-/*                     6       reserved (was EM_486) */
 #define EM_860         7       /* Intel i860. */
 #define EM_MIPS                8       /* MIPS R3000 Big-Endian only. */
-
-/* Extensions. */
 #define EM_S370                9       /* IBM System/370. */
-#define EM_MIPS_RS4_BE 10      /* MIPS R4000 Big-Endian */ /* Depreciated */
-/*                     11-14   reserved */
+#define EM_MIPS_RS3_LE 10      /* MIPS R3000 Little-Endian. */
 #define EM_PARISC      15      /* HP PA-RISC. */
-/*                     16      reserved */
 #define EM_VPP500      17      /* Fujitsu VPP500. */
 #define EM_SPARC32PLUS 18      /* SPARC v8plus. */
 #define EM_960         19      /* Intel 80960. */
 #define EM_PPC         20      /* PowerPC 32-bit. */
 #define EM_PPC64       21      /* PowerPC 64-bit. */
 #define EM_S390                22      /* IBM System/390. */
-/*                     23-35   reserved */
 #define EM_V800                36      /* NEC V800. */
 #define EM_FR20                37      /* Fujitsu FR20. */
 #define EM_RH32                38      /* TRW RH-32. */
 #define EM_RCE         39      /* Motorola RCE. */
 #define EM_ARM         40      /* ARM. */
-#define EM_ALPHA       41      /* Digital Alpha */
 #define EM_SH          42      /* Hitachi SH. */
 #define EM_SPARCV9     43      /* SPARC v9 64-bit. */
 #define EM_TRICORE     44      /* Siemens TriCore embedded processor. */
@@ -224,6 +219,12 @@ typedef struct {
 #define EM_ARCA                109     /* Arca RISC Microprocessor */
 #define EM_UNICORE     110     /* Microprocessor series from PKU-Unity Ltd. */
                                /* and MPRC of Peking University */
+
+/* Non-standard or deprecated. */
+#define EM_486         6       /* Intel i486. */
+#define EM_MIPS_RS4_BE 10      /* MIPS R4000 Big-Endian */
+#define EM_ALPHA_STD   41      /* Digital Alpha (standard value). */
+
 #define EM_NUM         111
 
 /* Special section indexes. */
@@ -239,52 +240,52 @@ typedef struct {
 #define SHN_HIRESERVE  0xffff          /* Last of reserved range. */
 
 /* sh_type */
-#define SHT_NULL       0               /* inactive */
-#define SHT_PROGBITS   1               /* program defined information */
-#define SHT_SYMTAB     2               /* symbol table section */
-#define SHT_STRTAB     3               /* string table section */
+#define SHT_NULL               0       /* inactive */
+#define SHT_PROGBITS           1       /* program defined information */
+#define SHT_SYMTAB             2       /* symbol table section */
+#define SHT_STRTAB             3       /* string table section */
 #define SHT_RELA               4       /* relocation section with addends */
-#define SHT_HASH       5               /* symbol hash table section */
-#define SHT_DYNAMIC    6               /* dynamic section */ 
-#define SHT_NOTE       7               /* note section */
-#define SHT_NOBITS     8               /* no space section */
+#define SHT_HASH               5       /* symbol hash table section */
+#define SHT_DYNAMIC            6       /* dynamic section */
+#define SHT_NOTE               7       /* note section */
+#define SHT_NOBITS             8       /* no space section */
 #define SHT_REL                        9       /* relocation section - no addends */
-#define SHT_SHLIB      10              /* reserved - purpose unknown */
-#define SHT_DYNSYM     11              /* dynamic symbol table section */ 
+#define SHT_SHLIB              10      /* reserved - purpose unknown */
+#define SHT_DYNSYM             11      /* dynamic symbol table section */
 #define SHT_INIT_ARRAY         14      /* Initialization function pointers. */
 #define SHT_FINI_ARRAY         15      /* Termination function pointers. */
 #define SHT_PREINIT_ARRAY      16      /* Pre-initialization function ptrs. */
 #define SHT_GROUP              17      /* Section group. */
 #define SHT_SYMTAB_SHNDX       18      /* Section indexes (see SHN_XINDEX). */
 
-#define SHT_NUM                19              /* number of section types */
+#define SHT_NUM                        19      /* number of section types */
 
-#define SHT_LOOS       0x60000000      /* First of OS specific semantics */
-#define SHT_HIOS       0x6fffffff      /* Last of OS specific semantics */
-#define SHT_LOPROC     0x70000000      /* reserved range for processor */
-#define SHT_HIPROC     0x7fffffff      /* specific section header types */
-#define SHT_LOUSER     0x80000000      /* reserved range for application */
-#define SHT_HIUSER     0xffffffff      /* specific indexes */
+#define SHT_LOOS               0x60000000      /* First of OS specific semantics */
+#define SHT_HIOS               0x6fffffff      /* Last of OS specific semantics */
+#define SHT_LOPROC             0x70000000      /* reserved range for processor */
+#define SHT_AMD64_UNWIND       0x70000001      /* unwind information */
+#define SHT_HIPROC             0x7fffffff      /* specific section header types */
+#define SHT_LOUSER             0x80000000      /* reserved range for application */
+#define SHT_HIUSER             0xffffffff      /* specific indexes */
 
 /* Flags for sh_flags. */
-#define SHF_WRITE      0x1             /* Section contains writable data. */
-#define SHF_ALLOC      0x2             /* Section occupies memory. */
-#define SHF_EXECINSTR  0x4             /* Section contains instructions. */
-#define SHF_MERGE      0x10            /* Section may be merged. */
-#define SHF_STRINGS    0x20            /* Section contains strings. */
+#define SHF_WRITE              0x1     /* Section contains writable data. */
+#define SHF_ALLOC              0x2     /* Section occupies memory. */
+#define SHF_EXECINSTR          0x4     /* Section contains instructions. */
+#define SHF_MERGE              0x10    /* Section may be merged. */
+#define SHF_STRINGS            0x20    /* Section contains strings. */
 #define SHF_INFO_LINK          0x40    /* sh_info holds section index. */
 #define SHF_LINK_ORDER         0x80    /* Special ordering requirements. */
 #define SHF_OS_NONCONFORMING   0x100   /* OS-specific processing required. */
-                                       /* handling */
-#define SHF_GROUP      0x200           /* Section is a member of a group. */
-#define SHF_TLS                0x400           /* Section contains TLS data. */
-#define SHF_MASKOS     0x0ff00000      /* Reserved for OS-specific. */
-#define SHF_MASKPROC   0xf0000000      /* Reserved for processor-specific. */
+#define SHF_GROUP              0x200   /* Member of section group. */
+#define SHF_TLS                        0x400   /* Section contains TLS data. */
+#define SHF_MASKOS     0x0ff00000      /* OS-specific semantics. */
+#define SHF_MASKPROC   0xf0000000      /* Processor-specific semantics. */
 
 /* Section group flags. */
 #define GRP_COMDAT     0x1             /* Group is a COMDAT. */
-#define SHF_MASKOS     0x0ff00000      /* OS-specific semantics. */
-#define SHF_MASKPROC   0xf0000000      /* Processor-specific semantics. */
+#define GRP_MASKOS     0x0ff00000      /* Reserved for OS-specific. */
+#define GRP_MASKPROC   0xf0000000      /* Reserved for processor-specific. */
 
 /* Values for p_type. */
 #define PT_NULL                0       /* Unused entry. */
@@ -294,11 +295,13 @@ typedef struct {
 #define PT_NOTE                4       /* Auxiliary information. */
 #define PT_SHLIB       5       /* Reserved (not used). */
 #define PT_PHDR                6       /* Location of program header itself. */
-#define        PT_TLS          7       /* Thread local storage segment */
+#define PT_TLS         7       /* Thread local storage segment */
 
 #define PT_COUNT       8       /* Number of defined p_type values. */
 
 #define PT_LOOS                0x60000000      /* First OS-specific. */
+#define PT_GNU_EH_FRAME        0x6474e550
+#define PT_GNU_STACK   0x6474e551
 #define PT_HIOS                0x6fffffff      /* Last OS-specific. */
 #define PT_LOPROC      0x70000000      /* First processor-specific type. */
 #define PT_HIPROC      0x7fffffff      /* Last processor-specific type. */
@@ -338,54 +341,110 @@ typedef struct {
 #define DT_TEXTREL     22      /* Indicates there may be relocations in
                                   non-writable segments. [sup] */
 #define DT_JMPREL      23      /* Address of PLT relocations. */
-#define        DT_BIND_NOW     24      /* [sup] */
-#define        DT_INIT_ARRAY   25      /* Address of the array of pointers to
+#define DT_BIND_NOW    24      /* [sup] */
+#define DT_INIT_ARRAY  25      /* Address of the array of pointers to
                                   initialization functions */
-#define        DT_FINI_ARRAY   26      /* Address of the array of pointers to
+#define DT_FINI_ARRAY  26      /* Address of the array of pointers to
                                   termination functions */
-#define        DT_INIT_ARRAYSZ 27      /* Size in bytes of the array of
+#define DT_INIT_ARRAYSZ        27      /* Size in bytes of the array of
                                   initialization functions. */
-#define        DT_FINI_ARRAYSZ 28      /* Size in bytes of the array of
+#define DT_FINI_ARRAYSZ        28      /* Size in bytes of the array of
                                   terminationfunctions. */
-#define        DT_RUNPATH      29      /* String table offset of a null-terminated
+#define DT_RUNPATH     29      /* String table offset of a null-terminated
                                   library search path string. */
-#define        DT_FLAGS        30      /* Object specific flag values. */
-#define        DT_ENCODING     32      /* Values greater than or equal to DT_ENCODING
+#define DT_FLAGS       30      /* Object specific flag values. */
+#define DT_ENCODING    32      /* Values greater than or equal to DT_ENCODING
                                   and less than DT_LOOS follow the rules for
                                   the interpretation of the d_un union
-                                  as follows: even == 'd_ptr', even == 'd_val'
+                                  as follows: even == 'd_ptr', odd == 'd_val'
                                   or none */
-#define        DT_PREINIT_ARRAY 32     /* Address of the array of pointers to
+#define DT_PREINIT_ARRAY 32    /* Address of the array of pointers to
                                   pre-initialization functions. */
-#define        DT_PREINIT_ARRAYSZ 33   /* Size in bytes of the array of
+#define DT_PREINIT_ARRAYSZ 33  /* Size in bytes of the array of
                                   pre-initialization functions. */
 
-#define        DT_COUNT        33      /* Number of defined d_tag values. */
+#define DT_COUNT       34      /* Number of defined d_tag values. */
+
+#define DT_LOOS                0x6000000d      /* First OS-specific */
+#define DT_HIOS                0x6fff0000      /* Last OS-specific */
 
-#define        DT_LOOS         0x6000000d      /* First OS-specific */
-#define        DT_HIOS         0x6fff0000      /* Last OS-specific */
-#define        DT_LOPROC       0x70000000      /* First processor-specific type. */
-#define        DT_HIPROC       0x7fffffff      /* Last processor-specific type. */
+/*
+ * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ * Dyn.d_un.d_val field of the Elf*_Dyn structure.
+ */
+#define DT_VALRNGLO    0x6ffffd00
+#define DT_CHECKSUM    0x6ffffdf8      /* elf checksum */
+#define DT_PLTPADSZ    0x6ffffdf9      /* pltpadding size */
+#define DT_MOVEENT     0x6ffffdfa      /* move table entry size */
+#define DT_MOVESZ      0x6ffffdfb      /* move table size */
+#define DT_FEATURE_1   0x6ffffdfc      /* feature holder */
+#define DT_POSFLAG_1   0x6ffffdfd      /* flags for DT_* entries, effecting */
+                                       /*      the following DT_* entry. */
+                                       /*      See DF_P1_* definitions */
+#define DT_SYMINSZ     0x6ffffdfe      /* syminfo table size (in bytes) */
+#define DT_SYMINENT    0x6ffffdff      /* syminfo entry size (in bytes) */
+#define DT_VALRNGHI    0x6ffffdff
+
+/*
+ * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+ *
+ * If any adjustment is made to the ELF object after it has been
+ * built, these entries will need to be adjusted.
+ */
+#define DT_ADDRRNGLO   0x6ffffe00
+#define DT_GNU_HASH    0x6ffffef5      /* GNU-style hash table */
+#define DT_CONFIG      0x6ffffefa      /* configuration information */
+#define DT_DEPAUDIT    0x6ffffefb      /* dependency auditing */
+#define DT_AUDIT       0x6ffffefc      /* object auditing */
+#define DT_PLTPAD      0x6ffffefd      /* pltpadding (sparcv9) */
+#define DT_MOVETAB     0x6ffffefe      /* move table */
+#define DT_SYMINFO     0x6ffffeff      /* syminfo table */
+#define DT_ADDRRNGHI   0x6ffffeff
+
+#define DT_VERSYM      0x6ffffff0      /* Address of versym section. */
+#define DT_RELACOUNT   0x6ffffff9      /* number of RELATIVE relocations */
+#define DT_RELCOUNT    0x6ffffffa      /* number of RELATIVE relocations */
+#define DT_FLAGS_1     0x6ffffffb      /* state flags - see DF_1_* defs */
+#define DT_VERDEF      0x6ffffffc      /* Address of verdef section. */
+#define DT_VERDEFNUM   0x6ffffffd      /* Number of elems in verdef section */
+#define DT_VERNEED     0x6ffffffe      /* Address of verneed section. */
+#define DT_VERNEEDNUM  0x6fffffff      /* Number of elems in verneed section */
+
+#define DT_LOPROC      0x70000000      /* First processor-specific type. */
+#define DT_AUXILIARY   0x7ffffffd      /* shared library auxiliary name */
+#define DT_USED                0x7ffffffe      /* ignored - same as needed */
+#define DT_FILTER      0x7fffffff      /* shared library filter name */
+#define DT_HIPROC      0x7fffffff      /* Last processor-specific type. */
 
 /* Values for DT_FLAGS */
-#define        DF_ORIGIN       0x0001  /* Indicates that the object being loaded may
+#define DF_ORIGIN      0x0001  /* Indicates that the object being loaded may
                                   make reference to the $ORIGIN substitution
                                   string */
-#define        DF_SYMBOLIC     0x0002  /* Indicates "symbolic" linking. */
-#define        DF_TEXTREL      0x0004  /* Indicates there may be relocations in
+#define DF_SYMBOLIC    0x0002  /* Indicates "symbolic" linking. */
+#define DF_TEXTREL     0x0004  /* Indicates there may be relocations in
                                   non-writable segments. */
-#define        DF_BIND_NOW     0x0008  /* Indicates that the dynamic linker should
+#define DF_BIND_NOW    0x0008  /* Indicates that the dynamic linker should
                                   process all relocations for the object
                                   containing this entry before transferring
                                   control to the program. */
-#define        DF_STATIC_TLS   0x0010  /* Indicates that the shared object or
+#define DF_STATIC_TLS  0x0010  /* Indicates that the shared object or
                                   executable contains code using a static
                                   thread-local storage scheme. */
 
+/* Values for DT_FLAGS_1 */
+#define DF_1_BIND_NOW  0x00000001      /* Same as DF_BIND_NOW */
+#define DF_1_GLOBAL    0x00000002      /* Set the RTLD_GLOBAL for object */
+#define DF_1_NODELETE  0x00000008      /* Set the RTLD_NODELETE for object */
+#define DF_1_LOADFLTR  0x00000010      /* Immediate loading of filtees */
+#define DF_1_NOOPEN    0x00000040      /* Do not allow loading on dlopen() */
+#define DF_1_ORIGIN    0x00000080      /* Process $ORIGIN */
+
 /* Values for n_type.  Used in core files. */
 #define NT_PRSTATUS    1       /* Process status. */
 #define NT_FPREGSET    2       /* Floating point registers. */
 #define NT_PRPSINFO    3       /* Process state info. */
+#define NT_THRMISC     7       /* Thread miscellaneous info. */
 
 /* Symbol Binding - ELFNN_ST_BIND - st_info */
 #define STB_LOCAL      0       /* Local symbol */
@@ -404,18 +463,41 @@ typedef struct {
 #define STT_FILE       4       /* Source file. */
 #define STT_COMMON     5       /* Uninitialized common block. */
 #define STT_TLS                6       /* TLS object. */
+#define STT_NUM                7
 #define STT_LOOS       10      /* Reserved range for operating system */
 #define STT_HIOS       12      /*   specific semantics. */
 #define STT_LOPROC     13      /* reserved range for processor */
 #define STT_HIPROC     15      /*   specific semantics. */
 
-/* Special symbol table indexes. */
-#define STN_UNDEF      0       /* Undefined symbol index. */
-
 /* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
 #define STV_DEFAULT    0x0     /* Default visibility (see binding). */
 #define STV_INTERNAL   0x1     /* Special meaning in relocatable objects. */
 #define STV_HIDDEN     0x2     /* Not visible. */
 #define STV_PROTECTED  0x3     /* Visible but not preemptible. */
+#define STV_EXPORTED   0x4
+#define STV_SINGLETON  0x5
+#define STV_ELIMINATE  0x6
+
+/* Special symbol table indexes. */
+#define        STN_UNDEF       0       /* Undefined symbol index. */
+
+/* Symbol versioning flags. */
+#define VER_DEF_CURRENT        1
+#define VER_DEF_IDX(x) VER_NDX(x)
+
+#define VER_FLG_BASE   0x01
+#define VER_FLG_WEAK   0x02
+
+#define VER_NEED_CURRENT       1
+#define VER_NEED_WEAK  (1u << 15)
+#define VER_NEED_HIDDEN        VER_NDX_HIDDEN
+#define VER_NEED_IDX(x)        VER_NDX(x)
+
+#define VER_NDX_LOCAL  0
+#define VER_NDX_GLOBAL 1
+#define VER_NDX_GIVEN  2
+
+#define VER_NDX_HIDDEN (1u << 15)
+#define VER_NDX(x)     ((x) & ~(1u << 15))
 
 #endif /* !_SYS_ELF_COMMON_H_ */
index 2bc04e4..4d07fb8 100644 (file)
@@ -64,8 +64,6 @@ __ElfType(Half);
 __ElfType(Off);
 __ElfType(Sword);
 __ElfType(Word);
-__ElfType(Size);
-__ElfType(Hashelt);
 __ElfType(Ehdr);
 __ElfType(Shdr);
 __ElfType(Phdr);
@@ -73,6 +71,15 @@ __ElfType(Dyn);
 __ElfType(Rel);
 __ElfType(Rela);
 __ElfType(Sym);
+__ElfType(Verdef);
+__ElfType(Verdaux);
+__ElfType(Verneed);
+__ElfType(Vernaux);
+__ElfType(Versym);
+
+/* Non-standard ELF types. */
+__ElfType(Hashelt);
+__ElfType(Size);
 
 #define ELF_R_SYM      __ELFN(R_SYM)
 #define ELF_R_TYPE     __ELFN(R_TYPE)
index c3b0802..4ec76ea 100644 (file)
@@ -27,7 +27,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/sys/link_elf.h,v 1.20.2.2 2003/02/20 20:42:46 kan Exp $
+ * $FreeBSD: src/sys/sys/link_elf.h,v 1.32 2011/01/08 17:11:49 kib Exp $
  */
 
 /*
@@ -41,9 +41,7 @@
 #ifndef _SYS_LINK_ELF_H_
 #define _SYS_LINK_ELF_H_
 
-#if (defined(FREEBSD_ELF) || defined(__ELF__)) && !defined(FREEBSD_AOUT)
-
-#include <sys/types.h>
+#include <elf.h>
 
 /*
  * Flags that describe the origin of the entries in Dl_serinfo.
@@ -78,253 +76,24 @@ struct r_debug {
        }               r_state;
 };
 
-#else /* !__ELF__ */
-
-struct dl_info;
-
-/*
- * A `Shared Object Descriptor' describes a shared object that is needed
- * to complete the link edit process of the object containing it.
- * A list of such objects (chained through `sod_next') is pointed at
- * by `sdt_sods' in the section_dispatch_table structure.
- */
-
-struct sod {   /* Shared Object Descriptor */
-       long    sod_name;               /* name (relative to load address) */
-       u_int   sod_library  : 1,       /* Searched for by library rules */
-               sod_reserved : 31;
-       short   sod_major;              /* major version number */
-       short   sod_minor;              /* minor version number */
-       long    sod_next;               /* next sod */
-};
-
-/*
- * `Shared Object Map's are used by the run-time link editor (ld.so) to
- * keep track of all shared objects loaded into a process' address space.
- * These structures are only used at run-time and do not occur within
- * the text or data segment of an executable or shared library.
- */
-struct so_map {                /* Shared Object Map */
-       caddr_t         som_addr;       /* Address at which object mapped */
-       char            *som_path;      /* Path to mmap'ed file */
-       struct so_map   *som_next;      /* Next map in chain */
-       struct sod      *som_sod;       /* Sod responsible for this map */
-       caddr_t         som_sodbase;    /* Base address of this sod */
-       u_int           som_write : 1;  /* Text is currently writable */
-       struct _dynamic *som_dynamic;   /* _dynamic structure */
-       caddr_t         som_spd;        /* Private data */
-};
-
-/*
- * Symbol description with size. This is simply an `nlist' with
- * one field (nz_size) added.
- * Used to convey size information on items in the data segment
- * of shared objects. An array of these live in the shared object's
- * text segment and is addressed by the `sdt_nzlist' field.
- */
-struct nzlist {
-       struct nlist    nlist;
-       u_long          nz_size;
-};
-
-#define nz_un          nlist.n_un
-#define nz_strx                nlist.n_un.n_strx
-#define nz_name                nlist.n_un.n_name
-#define nz_type                nlist.n_type
-#define nz_value       nlist.n_value
-#define nz_desc                nlist.n_desc
-#define nz_other       nlist.n_other
-
-/*
- * The `section_dispatch_table' structure contains offsets to various data
- * structures needed to do run-time relocation.
- */
-struct section_dispatch_table {
-       struct so_map *sdt_loaded;      /* List of loaded objects */
-       long    sdt_sods;               /* List of shared objects descriptors */
-       long    sdt_paths;              /* Library search paths */
-       long    sdt_got;                /* Global offset table */
-       long    sdt_plt;                /* Procedure linkage table */
-       long    sdt_rel;                /* Relocation table */
-       long    sdt_hash;               /* Symbol hash table */
-       long    sdt_nzlist;             /* Symbol table itself */
-       long    sdt_filler2;            /* Unused (was: stab_hash) */
-       long    sdt_buckets;            /* Number of hash buckets */
-       long    sdt_strings;            /* Symbol strings */
-       long    sdt_str_sz;             /* Size of symbol strings */
-       long    sdt_text_sz;            /* Size of text area */
-       long    sdt_plt_sz;             /* Size of procedure linkage table */
-};
-
-/*
- * RRS symbol hash table, addressed by `sdt_hash' in section_dispatch_table.
- * Used to quickly lookup symbols of the shared object by hashing
- * on the symbol's name. `rh_symbolnum' is the index of the symbol
- * in the shared object's symbol list (`sdt_nzlist'), `rh_next' is
- * the next symbol in the hash bucket (in case of collisions).
- */
-struct rrs_hash {
-       int     rh_symbolnum;           /* Symbol number */
-       int     rh_next;                /* Next hash entry */
-};
-
-/*
- * `rt_symbols' is used to keep track of run-time allocated commons
- * and data items copied from shared objects.
- */
-struct rt_symbol {
-       struct nzlist           *rt_sp;         /* The symbol */
-       struct rt_symbol        *rt_next;       /* Next in linear list */
-       struct rt_symbol        *rt_link;       /* Next in bucket */
-       caddr_t                 rt_srcaddr;     /* Address of "master" copy */
-       struct so_map           *rt_smp;        /* Originating map */
-};
-
-/*
- * Debugger interface structure.
- */
-struct so_debug {
-       int     dd_version;             /* Version # of interface */
-       int     dd_in_debugger;         /* Set when run by debugger */
-       int     dd_sym_loaded;          /* Run-time linking brought more
-                                          symbols into scope */
-       char     *dd_bpt_addr;          /* Address of rtld-generated bpt */
-       int     dd_bpt_shadow;          /* Original contents of bpt */
-       struct rt_symbol *dd_cc;        /* Allocated commons/copied data */
-};
-
-/*
- * Version returned to crt0 from ld.so
- */
-#define LDSO_VERSION_NONE      0       /* FreeBSD2.0, 2.0.5 */
-#define LDSO_VERSION_HAS_DLEXIT        1       /* includes dlexit in ld_entry */
-#define LDSO_VERSION_HAS_DLSYM3        2       /* includes 3-argument dlsym */
-#define LDSO_VERSION_HAS_DLADDR        3       /* includes dladdr in ld_entry */
-
-/*
- * Entry points into ld.so - user interface to the run-time linker.
- * Entries are valid for the given version numbers returned by ld.so
- * to crt0.
- */
-struct ld_entry {
-       void    *(*dlopen) (const char *, int); /* NONE */
-       int     (*dlclose) (void *);            /* NONE */
-       void    *(*dlsym) (void *, const char *);       /* NONE */
-       const char *(*dlerror) (void);          /* NONE */
-       void    (*dlexit) (void);                       /* HAS_DLEXIT */
-       void    *(*dlsym3) (void *, const char *, void *); /* HAS_DLSYM3 */
-       int      (*dladdr) (const void *,
-                               struct dl_info *);      /* HAS_DLADDR */
-};
-
-/*
- * This is the structure pointed at by the __DYNAMIC symbol if an
- * executable requires the attention of the run-time link editor.
- * __DYNAMIC is given the value zero if no run-time linking needs to
- * be done (it is always present in shared objects).
- * The union `d_un' provides for different versions of the dynamic
- * linking mechanism (switched on by `d_version'). The last version
- * used by Sun is 3. We leave some room here and go to version number
- * 8 for NetBSD, the main difference lying in the support for the
- * `nz_list' type of symbols.
- */
-
-struct _dynamic {
-       int             d_version;      /* version # of this interface */
-       struct so_debug *d_debug;
-       union {
-               struct section_dispatch_table *d_sdt;
-       } d_un;
-       struct ld_entry *d_entry;       /* XXX */
-};
-
-#define LD_VERSION_SUN         (3)
-#define LD_VERSION_BSD         (8)
-#define LD_VERSION_NZLIST_P(v) ((v) >= 8)
-
-#define LD_GOT(x)      ((x)->d_un.d_sdt->sdt_got)
-#define LD_PLT(x)      ((x)->d_un.d_sdt->sdt_plt)
-#define LD_REL(x)      ((x)->d_un.d_sdt->sdt_rel)
-#define LD_SYMBOL(x)   ((x)->d_un.d_sdt->sdt_nzlist)
-#define LD_HASH(x)     ((x)->d_un.d_sdt->sdt_hash)
-#define LD_STRINGS(x)  ((x)->d_un.d_sdt->sdt_strings)
-#define LD_NEED(x)     ((x)->d_un.d_sdt->sdt_sods)
-#define LD_BUCKETS(x)  ((x)->d_un.d_sdt->sdt_buckets)
-#define LD_PATHS(x)    ((x)->d_un.d_sdt->sdt_paths)
-
-#define LD_GOTSZ(x)    ((x)->d_un.d_sdt->sdt_plt - (x)->d_un.d_sdt->sdt_got)
-#define LD_RELSZ(x)    ((x)->d_un.d_sdt->sdt_hash - (x)->d_un.d_sdt->sdt_rel)
-#define LD_HASHSZ(x)   ((x)->d_un.d_sdt->sdt_nzlist - (x)->d_un.d_sdt->sdt_hash)
-#define LD_STABSZ(x)   ((x)->d_un.d_sdt->sdt_strings - (x)->d_un.d_sdt->sdt_nzlist)
-#define LD_PLTSZ(x)    ((x)->d_un.d_sdt->sdt_plt_sz)
-#define LD_STRSZ(x)    ((x)->d_un.d_sdt->sdt_str_sz)
-#define LD_TEXTSZ(x)   ((x)->d_un.d_sdt->sdt_text_sz)
-
-/*
- * Interface to ld.so
- */
-struct crt_ldso {
-       int             crt_ba;         /* Base address of ld.so */
-       int             crt_dzfd;       /* "/dev/zero" file descriptor (SunOS) */
-       int             crt_ldfd;       /* ld.so file descriptor */
-       struct _dynamic *crt_dp;        /* Main's __DYNAMIC */
-       char            **crt_ep;       /* environment strings */
-       caddr_t         crt_bp;         /* Breakpoint if run from debugger */
-       char            *crt_prog;      /* Program name (v3) */
-       char            *crt_ldso;      /* Link editor name (v4) */
-       struct ld_entry *crt_ldentry;   /* dl*() access (v4) */
-       char            **crt_argv;     /* argument strings (v5) */
-};
-
-/*
- * Version passed from crt0 to ld.so (1st argument to _rtld()).
- */
-#define CRT_VERSION_SUN                1
-#define CRT_VERSION_BSD_2      2
-#define CRT_VERSION_BSD_3      3
-#define CRT_VERSION_BSD_4      4
-#define CRT_VERSION_BSD_5      5
-
-/*
- * Maximum number of recognized shared object version numbers.
- */
-#define MAXDEWEY       8
-
-/*
- * Header of the hints file.
- */
-struct hints_header {
-       long            hh_magic;
-#define HH_MAGIC       011421044151
-       long            hh_version;     /* Interface version number */
-#define LD_HINTS_VERSION_1     1
-#define LD_HINTS_VERSION_2     2
-       long            hh_hashtab;     /* Location of hash table */
-       long            hh_nbucket;     /* Number of buckets in hashtab */
-       long            hh_strtab;      /* Location of strings */
-       long            hh_strtab_sz;   /* Size of strings */
-       long            hh_ehints;      /* End of hints (max offset in file) */
-       long            hh_dirlist;     /* Colon-separated list of srch dirs */
+struct dl_phdr_info
+{
+   Elf_Addr               dlpi_addr;     /* module relocation base */
+   const char            *dlpi_name;     /* module name */
+   const Elf_Phdr        *dlpi_phdr;     /* pointer to module's phdr */
+   Elf_Half               dlpi_phnum;    /* number of entries in phdr */
+   unsigned long long int dlpi_adds;     /* total # of loads */
+   unsigned long long int dlpi_subs;     /* total # of unloads */
+   size_t                 dlpi_tls_modid;
+   void                  *dlpi_tls_data;
 };
 
-#define HH_BADMAG(hdr) ((hdr).hh_magic != HH_MAGIC)
-
-/*
- * Hash table element in hints file.
- */
-struct hints_bucket {
-       /* namex and pathx are indices into the string table */
-       int             hi_namex;               /* Library name */
-       int             hi_pathx;               /* Full path */
-       int             hi_dewey[MAXDEWEY];     /* The vers