diff options
author | Rod Evans <Rod.Evans@Sun.COM> | 2009-05-08 10:36:22 -0700 |
---|---|---|
committer | Rod Evans <Rod.Evans@Sun.COM> | 2009-05-08 10:36:22 -0700 |
commit | 2017c9656f884256b400be40fa25d96d630bf02a (patch) | |
tree | 3595b8a5a17d9c3e47ec41e5214458d7a2912efb /usr/src | |
parent | b57459abfba36eb3068cfe44c6921168b4c4f774 (diff) | |
download | illumos-gate-2017c9656f884256b400be40fa25d96d630bf02a.tar.gz |
6831308 ld.so.1: symbol rescanning does a little too much work
Diffstat (limited to 'usr/src')
40 files changed, 1170 insertions, 438 deletions
diff --git a/usr/src/cmd/sgs/include/alist.h b/usr/src/cmd/sgs/include/alist.h index d020feb15a..c5071a8cd2 100644 --- a/usr/src/cmd/sgs/include/alist.h +++ b/usr/src/cmd/sgs/include/alist.h @@ -229,7 +229,7 @@ typedef struct { * Possible values returned by aplist_test() */ typedef enum { - ALE_ALLOCFAIL = 0, /* Memory allocation error */ + ALE_ALLOCFAIL = 0, /* memory allocation error */ ALE_EXISTS = 1, /* alist entry already exists */ ALE_NOTFND = 2, /* item not found and insert not required */ ALE_CREATE = 3 /* alist entry created */ diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h index 28df496cd8..93c2d2ce39 100644 --- a/usr/src/cmd/sgs/include/conv.h +++ b/usr/src/cmd/sgs/include/conv.h @@ -193,7 +193,7 @@ typedef union { } Conv_grphdl_flags_buf_t; /* conv_grpdesc_flags() */ -#define CONV_GRPDESC_FLAGS_BUFSIZE 102 +#define CONV_GRPDESC_FLAGS_BUFSIZE 91 typedef union { Conv_inv_buf_t inv_buf; char buf[CONV_GRPDESC_FLAGS_BUFSIZE]; @@ -251,8 +251,8 @@ typedef union { /* conv_phdr_flags() */ #define CONV_PHDR_FLAGS_BUFSIZE 57 typedef union { - Conv_inv_buf_t inv_buf; - char buf[CONV_PHDR_FLAGS_BUFSIZE]; + Conv_inv_buf_t inv_buf; + char buf[CONV_PHDR_FLAGS_BUFSIZE]; } Conv_phdr_flags_buf_t; /* conv_sec_flags() */ @@ -354,7 +354,16 @@ typedef union { char buf[CONV_VER_FLAGS_BUFSIZE]; } Conv_ver_flags_buf_t; - +/* + * conv_time() + * + * This size is based on the maximum "hour.min.sec.fraction: " time that + * would be expected of ld(). + */ +#define CONV_TIME_BUFSIZE 18 +typedef union { + char buf[CONV_TIME_BUFSIZE]; +} Conv_time_buf_t; /* * Many conversion routines accept a fmt_flags argument of this type @@ -852,6 +861,8 @@ extern const char *conv_syminfo_boundto(Half, Conv_fmt_flags_t, Conv_inv_buf_t *); extern const char *conv_syminfo_flags(Half, Conv_fmt_flags_t, Conv_syminfo_flags_buf_t *); +extern const char *conv_time(struct timeval *, struct timeval *, + Conv_time_buf_t *); extern Uts_desc *conv_uts(void); extern const char *conv_ver_flags(Half, Conv_fmt_flags_t, Conv_ver_flags_buf_t *); diff --git a/usr/src/cmd/sgs/include/debug.h b/usr/src/cmd/sgs/include/debug.h index d8db81bddb..4f0c68e851 100644 --- a/usr/src/cmd/sgs/include/debug.h +++ b/usr/src/cmd/sgs/include/debug.h @@ -43,6 +43,7 @@ * start with the `Elf_' prefix. These latter routines are the only * routines used by the elfdump(1) utility. */ +#include <sys/times.h> #include <sgs.h> #include <libld.h> #include <rtld.h> @@ -160,6 +161,10 @@ typedef struct { uint_t d_class; /* debugging classes */ uint_t d_extra; /* extra public information */ APlist *d_list; /* accepted link-map list names */ + struct timeval d_totaltime; /* total time since entry - */ + /* gettimeofday(3c) */ + struct timeval d_deltatime; /* delta time since last diagnostic - */ + /* gettimeofday(3c) */ } Dbg_desc; extern Dbg_desc *dbg_desc; @@ -180,6 +185,9 @@ extern Dbg_desc *dbg_desc; #define DBG_E_STDNL 0x00000008 /* standard newline indicator */ #define DBG_E_HELP 0x00000010 /* help requested */ #define DBG_E_HELP_EXIT 0x00000020 /* hint: user should exit after help */ +#define DBG_E_TTIME 0x00000040 /* prepend total time */ +#define DBG_E_DTIME 0x00000080 /* prepend delta time */ +#define DBG_E_RESET 0x00000100 /* reset times */ /* ld only */ #define DBG_E_SNAME 0x00001000 /* prepend simple name */ @@ -197,12 +205,25 @@ extern Dbg_desc *dbg_desc; #define DBG_NOTDETAIL() !(dbg_desc->d_extra & DBG_E_DETAIL) #define DBG_NOTLONG() !(dbg_desc->d_extra & DBG_E_LONG) +#define DBG_ISDEMANGLE() \ + (dbg_desc->d_extra & DBG_E_DEMANGLE) + +#define DBG_TOTALTIME (dbg_desc->d_totaltime) +#define DBG_DELTATIME (dbg_desc->d_deltatime) + +#define DBG_ISTTIME() (dbg_desc->d_extra & DBG_E_TTIME) +#define DBG_ISDTIME() (dbg_desc->d_extra & DBG_E_DTIME) +#define DBG_ISTIME() (dbg_desc->d_extra & (DBG_E_TTIME | DBG_E_DTIME)) +#define DBG_NOTTIME() !(dbg_desc->d_extra & (DBG_E_TTIME | DBG_E_DTIME)) + +#define DBG_ISRESET() (dbg_desc->d_extra & DBG_E_RESET) +#define DBG_ONRESET() (dbg_desc->d_extra |= DBG_E_RESET) +#define DBG_OFFRESET() (dbg_desc->d_extra &= ~DBG_E_RESET) + #define DBG_ISSNAME() (dbg_desc->d_extra & DBG_E_SNAME) #define DBG_ISFNAME() (dbg_desc->d_extra & DBG_E_FNAME) #define DBG_ISCLASS() (dbg_desc->d_extra & DBG_E_CLASS) #define DBG_ISLMID() (dbg_desc->d_extra & DBG_E_LMID) -#define DBG_ISDEMANGLE() \ - (dbg_desc->d_extra & DBG_E_DEMANGLE) /* * Print routine, this must be supplied by the application. The initial @@ -648,8 +669,8 @@ extern void Dbg_help(void); /* * External Dbg_*() interface routines. */ -extern void Dbg_args_files(Lm_list *, int, char *); -extern void Dbg_args_opts(Lm_list *, int, int, char *); +extern void Dbg_args_file(Lm_list *, int, char *); +extern void Dbg_args_option(Lm_list *, int, int, char *); extern void Dbg_args_str2chr(Lm_list *, int, const char *, int); extern void Dbg_args_Wldel(Lm_list *, int, const char *); extern void Dbg_audit_ignore(Rt_map *); @@ -662,6 +683,14 @@ extern void Dbg_audit_skip(Lm_list *, const char *, const char *); extern void Dbg_audit_terminate(Lm_list *, const char *); extern void Dbg_audit_version(Lm_list *, const char *, ulong_t); +extern void Dbg_basic_collect(Lm_list *); +extern void Dbg_basic_create(Lm_list *); +extern void Dbg_basic_finish(Lm_list *); +extern void Dbg_basic_files(Lm_list *); +extern void Dbg_basic_options(Lm_list *); +extern void Dbg_basic_relocate(Lm_list *); +extern void Dbg_basic_validate(Lm_list *); + extern void Dbg_bind_global(Rt_map *, Addr, Off, Xword, Pltbindtype, Rt_map *, Addr, Off, const char *, uint_t); extern void Dbg_bind_plt_summary(Lm_list *, Half, Word, Word, Word, Word, @@ -885,9 +914,9 @@ extern void Dbg_util_intoolate(Rt_map *); extern void Dbg_util_lcinterface(Rt_map *, int, char *); extern void Dbg_util_nl(Lm_list *, int); extern void Dbg_util_no_init(Rt_map *); -extern void Dbg_util_str(Lm_list *, const char *); extern void Dbg_util_scc_entry(Rt_map *, uint_t); extern void Dbg_util_scc_title(Lm_list *, int); +extern void Dbg_util_str(Lm_list *, const char *); extern void Dbg_unused_file(Lm_list *, const char *, int, uint_t); extern void Dbg_unused_lcinterface(Rt_map *, Rt_map *, int); diff --git a/usr/src/cmd/sgs/include/rtld.h b/usr/src/cmd/sgs/include/rtld.h index b350a63f3c..99fd1ea355 100644 --- a/usr/src/cmd/sgs/include/rtld.h +++ b/usr/src/cmd/sgs/include/rtld.h @@ -63,6 +63,28 @@ typedef struct slookup Slookup; /* * A binding descriptor. Establishes the binding relationship between two * objects, the caller (originator) and the dependency (destination). + * + * Every relationship between two objects is tracked by a binding descriptor. + * This descriptor is referenced from a link-map's DEPENDS and CALLERS lists. + * Note, Aplist's are diagramed to fully expose the allocations required to + * establish the data structure relationships. + * + * Bnd_desc + * ---------- + * ------------| b_caller | + * | | b_depend | ---------- + * | | | | + * Rt_map | ---------- | Rt_map + * ---------- | ^ ^ | ---------- + * | | <-- | | --> | | + * | | -------- | | | | + * | DEPENDS | ----> | | | | -------- | | + * | | | | | | | | <---- | CALLERS | + * | | | | --- | | | | | + * | | | | --- | | | | + * | | -------- | | | | + * ---------- Aplist -------- ---------- + * Aplist */ typedef struct { Rt_map *b_caller; /* caller (originator) of a binding */ @@ -75,8 +97,8 @@ typedef struct { #define BND_NEEDED 0x0001 /* caller NEEDED the dependency */ #define BND_REFER 0x0002 /* caller relocation references the */ /* dependency */ -#define BND_FILTER 0x0004 /* pseudo binding to identify filter */ - +#define BND_FILTER 0x0004 /* binding identifies filter, used */ + /* for diagnostics only */ /* * Private structure for communication between rtld_db and rtld. * @@ -182,7 +204,7 @@ typedef struct { * | | | lc_head | -- ------ | ------ * | | | lc_tail | ------------------ * | | |---------| - * | lc_head | + * ---------- | lc_head | * | lc_tail | * |---------| * @@ -393,31 +415,56 @@ struct lm_list32 { * * The capability of ld.so.1 to associate a group of objects, look for symbols * within that group, ensure that groups are isolated from one another (with - * regard to relocations), and to unload a group, centers around a handle. This - * data structure is tracked from the link-map HANDLE(), and is the structure - * returned from dlopen(), and similar object loading capabilities such as - * filter/filtee processing. + * regard to relocations), and to unload a group, centers around a handle. + * + * Dependencies can be added to an existing handle as the dependencies are + * lazily loaded. The core dependencies on the handle are the ldd(1) list of + * the referenced object. + * + * Handles can be created from: + * + * - a dlopen() request. This associates a caller to a reference object, + * and the referenced objects dependencies. This group of objects can + * then be inspected for symbols (dlsym()). + * - a filtering request. This associates a filter (caller) to a referenced + * object (filtee). The redirection of filter symbols to their filtee + * counterpart is essentially a dlsym() using the filtee's handle. * - * A handle keeps track of all the dependencies of the associated object. - * These dependencies may be added as objects are lazily loaded. The core - * dependencies on the handle are the ldd(1) list of the associated object. - * The object assigned the handle, and the parent (or caller) who requested the - * handle are also maintained as dependencies on the handle. + * The handle created for these events is referred to as a public handle. This + * handle tracks the referenced object, all of the dependencies of the + * referenced object, and the caller (parent). * * Presently, an object may have two handles, one requested with RTLD_FIRST * and one without. * - * A handle may be referenced by any number of parents (callers). A reference + * A handle may be referenced by any number of callers (parents). A reference * count tracks the number. A dlclose() operation drops the reference count, * and when the count is zero, the handle is used to determine the family of * objects to unload. As bindings may occur to objects on the handle from - * other handles, it may not be possible to remove a complete family of - * objects or that handle itself. Handles in this state are moved to an orphan - * list. A handle on the orphan list is taken off the orphan list if the - * associated object is reopened. Otherwise, the handle remains on the orphan - * list for the duration of the process. The orphan list is inspected any time - * objects are unloaded, to determine if the orphaned objects can also be - * unloaded. + * other handles, it may not be possible to remove a complete family of objects + * or the handle itself. Handles in this state are moved to an orphan list. + * A handle on the orphan list is taken off the orphan list if the associated + * object is reopened. Otherwise, the handle remains on the orphan list for + * the duration of the process. The orphan list is inspected any time objects + * are unloaded, to determine if the orphaned objects can also be unloaded. + * + * Handles can also be created for internal uses: + * + * - to promote objects to RTLD_NOW. + * - to establish families for symbol binding fallback, required when lazy + * loadable objects are still pending. + * + * The handle created for these events is referred to as a private handle. This + * handle does not need to track the caller (parent), and because of this, does + * not need to be considered during dlclose() operations, as the handle can not + * be referenced by callers outside of the referenced objects family. + * + * Note, a private handle is essentially a subset of a public handle. Should + * an internal operation require a private handle, and a public handle already + * exist, the public handle can be used. Should an external operation require + * a public handle, and a private handle exist, the private handle is promoted + * to a public handle. Any handle that gets created will remain in existence + * for the life time of the referenced object. * * Objects can be dlopened using RTLD_NOW. This attribute requires that all * relocations of the object, and its dependencies are processed immediately, @@ -427,9 +474,53 @@ struct lm_list32 { * RTLD_NOW request is made, then the object, and its dependencies, most undergo * additional relocation processing. This promotion from lazy binding to * immediate binding is carried out using handles, as the handle defines the - * dependencies that must be processed. A temporary handle is created for this - * purpose, and is discarded immediately after the promotion operation has been - * completed. + * dependencies that must be processed. + * + * To ensure that objects within a lazy loadable environment can be relocated, + * no matter whether the objects have their dependencies described completely, + * a symbol lookup fallback is employed. Any pending lazy loadable objects are + * loaded, and a handle established to search the object and it's dependencies + * for the required symbol. + * + * A group handle (and its associated group descriptors), is referenced from + * a link-map's HANDLES and GROUPS lists. Note, Aplist's are diagramed to + * fully expose the allocations required to establish the data structure + * relationships. + * + * Grp_desc + * Alist + * ----------- + * --> | | + * | |-----------| + * | | gd_depend | --------- + * | | | | + * | |-----------| | + * --------|--- | gd_depend | | + * | | | (parent) | | + * | | |-----------| | + * | | | gd_depend | | + * | | | | | + * | | | | | + * | | ----------- | + * | | | + * | | Grp_hdl | + * | | ----------- | + * | -- | gh_depends | | + * | --------- | gh_ownlmp | | + * | | | | | + * | | | | | + * | | | | | + * Rt_map | | ------------ | Rt_map + * ---------- | | ^ ^ | ---------- + * | | <- | | | --> | | + * | | <--- -------- | | | | + * | HANDLES | ----> | | | | -------- | | + * | | | | | | | | <---- | GROUPS | + * | | | | --- | | | | | + * | | | | --- | | | | + * | | -------- | | | | + * ---------- Aplist -------- ---------- + * Aplist */ typedef struct { Alist *gh_depends; /* handle dependency list */ @@ -439,15 +530,27 @@ typedef struct { uint_t gh_flags; /* handle flags (GPH_ values) */ } Grp_hdl; -#define GPH_ZERO 0x0001 /* special handle for dlopen(0) */ -#define GPH_LDSO 0x0002 /* special handle for ld.so.1 */ -#define GPH_FIRST 0x0004 /* dlsym() can only use originating */ +/* + * Define the two categories of handle. + */ +#define GPH_PUBLIC 0x0001 /* handle returned to caller(s) */ +#define GPH_PRIVATE 0x0002 /* handle used internally */ + +/* + * Define any flags that affects how the handle is used. + */ +#define GPH_ZERO 0x0010 /* special handle for dlopen(0) */ +#define GPH_LDSO 0x0020 /* special handle for ld.so.1 */ +#define GPH_FIRST 0x0040 /* dlsym() can only use originating */ /* dependency */ -#define GPH_FILTEE 0x0008 /* handle used to specify a filtee */ -#define GPH_INITIAL 0x0010 /* handle is initialized */ -#define GPH_NOPENDLAZY 0x0020 /* no pending lazy dependencies */ +#define GPH_FILTEE 0x0080 /* handle identifies a filtee, used */ + /* for diagnostics only */ +/* + * Define any state that is associated with the handle. + */ +#define GPH_INITIAL 0x0100 /* handle is initialized */ +#define GPH_NOPENDLAZY 0x0200 /* no pending lazy dependencies */ /* remain for this handle */ - /* * Define a Group Descriptor. * @@ -467,10 +570,10 @@ typedef struct { /* should be added to handle */ #define GPD_PARENT 0x0008 /* dependency is a parent */ #define GPD_FILTER 0x0010 /* dependency is our filter */ -#define GPD_PROMOTE 0x0020 /* dependency is our RTLD_NOW */ - /* promoter */ -#define GPD_REMOVE 0x1000 /* descriptor is a candidate for */ +#define GPD_REMOVE 0x0100 /* descriptor is a candidate for */ /* removal from the group */ +#define GPD_MODECHANGE 0x0200 /* dependency mode has changed, e.g. */ + /* promoted to RTLD_GOBAL */ /* * Define threading structures. For compatibility with libthread (T1_VERSION 1 @@ -728,11 +831,11 @@ typedef struct rt_map32 { #define MSK_RT_INTPOSE 0x01800000 /* mask for all interposer */ /* possibilities */ #define FLG_RT_MOVE 0x02000000 /* object needs move operation */ -#define FLG_RT_TMPLIST 0x04000000 /* object is part of a temporary list */ +#define FLG_RT_RELOCING 0x04000000 /* object is being relocated */ #define FLG_RT_REGSYMS 0x08000000 /* object has DT_REGISTER entries */ #define FLG_RT_INITCLCT 0x10000000 /* init has been collected (tsort) */ -#define FLG_RT_HANDLE 0x20000000 /* generate a handle for this object */ -#define FLG_RT_RELOCING 0x40000000 /* object is being relocated */ +#define FLG_RT_PUBHDL 0x20000000 /* generate a handle for this object */ +#define FLG_RT_PRIHDL 0x40000000 /* either public or private */ #define FL1_RT_COPYTOOK 0x00000001 /* copy relocation taken */ diff --git a/usr/src/cmd/sgs/libconv/Makefile.com b/usr/src/cmd/sgs/libconv/Makefile.com index 35875f0358..68a360da5f 100644 --- a/usr/src/cmd/sgs/libconv/Makefile.com +++ b/usr/src/cmd/sgs/libconv/Makefile.com @@ -47,7 +47,8 @@ COMOBJS= arch.o c_literal.o \ relocate_sparc.o sections.o \ segments.o strproc.o \ symbols.o syminfo.o \ - tokens.o version.o + tokens.o time.o \ + version.o ELFCAP_OBJS= elfcap.o @@ -65,7 +66,8 @@ BLTOBJS= arch_msg.o c_literal_msg.o \ relocate_i386_msg.o relocate_sparc_msg.o \ sections_msg.o segments_msg.o \ symbols_msg.o symbols_sparc_msg.o \ - syminfo_msg.o version_msg.o + syminfo_msg.o time_msg.o \ + version_msg.o OBJECTS = $(COMOBJS) $(COMOBJS32) $(COMOBJS64) $(ELFCAP_OBJS) \ diff --git a/usr/src/cmd/sgs/libconv/common/group.c b/usr/src/cmd/sgs/libconv/common/group.c index c0e09d99db..3fb596b059 100644 --- a/usr/src/cmd/sgs/libconv/common/group.c +++ b/usr/src/cmd/sgs/libconv/common/group.c @@ -60,6 +60,8 @@ const char * conv_grphdl_flags(uint_t flags, Conv_grphdl_flags_buf_t *grphdl_flags_buf) { static const Val_desc vda[] = { + { GPH_PUBLIC, MSG_GPH_PUBLIC }, + { GPH_PRIVATE, MSG_GPH_PRIVATE }, { GPH_ZERO, MSG_GPH_ZERO }, { GPH_LDSO, MSG_GPH_LDSO }, { GPH_FIRST, MSG_GPH_FIRST }, @@ -118,8 +120,8 @@ conv_grpdesc_flags(uint_t flags, Conv_grpdesc_flags_buf_t *grpdesc_flags_buf) { GPD_ADDEPS, MSG_GPD_ADDEPS }, { GPD_PARENT, MSG_GPD_PARENT }, { GPD_FILTER, MSG_GPD_FILTER }, - { GPD_PROMOTE, MSG_GPD_PROMOTE }, { GPD_REMOVE, MSG_GPD_REMOVE }, + { GPD_MODECHANGE, MSG_GPD_MODECHANGE }, { 0, 0 } }; static CONV_EXPN_FIELD_ARG conv_arg = { diff --git a/usr/src/cmd/sgs/libconv/common/group.msg b/usr/src/cmd/sgs/libconv/common/group.msg index e98cf79c03..c49c6e7283 100644 --- a/usr/src/cmd/sgs/libconv/common/group.msg +++ b/usr/src/cmd/sgs/libconv/common/group.msg @@ -20,11 +20,12 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" +@ MSG_GPH_PUBLIC "GPH_PUBLIC" +@ MSG_GPH_PRIVATE "GPH_PRIVATE" @ MSG_GPH_ZERO "GPH_ZERO" @ MSG_GPH_LDSO "GPH_LDSO" @ MSG_GPH_FIRST "GPH_FIRST" @@ -37,7 +38,7 @@ @ MSG_GPD_ADDEPS "GPD_ADDEPS" @ MSG_GPD_PARENT "GPD_PARENT" @ MSG_GPD_FILTER "GPD_FILTER" -@ MSG_GPD_PROMOTE "GPD_PROMOTE" @ MSG_GPD_REMOVE "GPD_REMOVE" +@ MSG_GPD_MODECHANGE "GPD_MODECHANGE" @ MSG_GBL_NULL "" diff --git a/usr/src/cmd/sgs/libconv/common/lintsup.c b/usr/src/cmd/sgs/libconv/common/lintsup.c index b05e76e13c..306f562f63 100644 --- a/usr/src/cmd/sgs/libconv/common/lintsup.c +++ b/usr/src/cmd/sgs/libconv/common/lintsup.c @@ -78,6 +78,7 @@ #include "symbols_msg.h" #include "symbols_sparc_msg.h" #include "syminfo_msg.h" +#include "time_msg.h" #include "version_msg.h" void @@ -110,6 +111,7 @@ foo() USE(_sgs_msg_libconv_symbols); USE(_sgs_msg_libconv_symbols_sparc); USE(_sgs_msg_libconv_syminfo); + USE(_sgs_msg_libconv_time); USE(_sgs_msg_libconv_version); #undef USE diff --git a/usr/src/cmd/sgs/libconv/common/llib-lconv b/usr/src/cmd/sgs/libconv/common/llib-lconv index 2f2c28bce7..58b2f65b39 100644 --- a/usr/src/cmd/sgs/libconv/common/llib-lconv +++ b/usr/src/cmd/sgs/libconv/common/llib-lconv @@ -170,6 +170,8 @@ const char *conv_sym_other_vis(uchar_t, Conv_fmt_flags_t, const char *conv_syminfo_boundto(Half, Conv_fmt_flags_t, Conv_inv_buf_t *); const char *conv_syminfo_flags(Half, Conv_fmt_flags_t, Conv_syminfo_flags_buf_t *); +const char *conv_time(struct timeval *, struct timeval *, + Conv_time_buf_t *); Uts_desc *conv_uts(void); const char *conv_ver_flags(Half, Conv_fmt_flags_t, Conv_ver_flags_buf_t *); const char *conv_ver_index(Versym, int, Conv_inv_buf_t *); diff --git a/usr/src/cmd/sgs/libconv/common/time.c b/usr/src/cmd/sgs/libconv/common/time.c new file mode 100644 index 0000000000..042f69c008 --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/time.c @@ -0,0 +1,73 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/time.h> +#include <string.h> +#include <stdio.h> +#include "_conv.h" +#include "time_msg.h" + +/* + * Translate a struct timeval into a string appropriate for ld(1) and ld.so.1(1) + * diagnostics. + */ +const char * +conv_time(struct timeval *oldtime, struct timeval *newtime, + Conv_time_buf_t *time_buf) +{ + int hour, min; + time_t sec; + suseconds_t usec; + + sec = newtime->tv_sec - oldtime->tv_sec; + if (newtime->tv_usec >= oldtime->tv_usec) + usec = newtime->tv_usec - oldtime->tv_usec; + else { + usec = (newtime->tv_usec + MICROSEC) - oldtime->tv_usec; + sec -= 1; + } + + /* + * The default display is "sec.fraction", but ld(1) has been know to + * ascend into minutes, and in worst case scenarios, hours. + */ + if ((min = sec / 60) != 0) + sec = sec % 60; + if ((hour = min / 60) != 0) + min = min % 60; + + if (hour) + (void) snprintf(time_buf->buf, sizeof (time_buf->buf), + MSG_ORIG(MSG_TIME_HMSF), hour, min, sec, usec); + else if (min) + (void) snprintf(time_buf->buf, sizeof (time_buf->buf), + MSG_ORIG(MSG_TIME_MSF), min, sec, usec); + else + (void) snprintf(time_buf->buf, sizeof (time_buf->buf), + MSG_ORIG(MSG_TIME_SF), sec, usec); + + return ((const char *)time_buf); +} diff --git a/usr/src/cmd/sgs/libconv/common/time.msg b/usr/src/cmd/sgs/libconv/common/time.msg new file mode 100644 index 0000000000..659f04d7c0 --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/time.msg @@ -0,0 +1,28 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Message file for cmd/sgs/libconv/common/time.c + +@ MSG_TIME_HMSF "%d.%d.%.2ld.%.6ld: " +@ MSG_TIME_MSF "%d.%.2ld.%.6ld: " +@ MSG_TIME_SF "%.2ld.%.6ld: " diff --git a/usr/src/cmd/sgs/libld/common/args.c b/usr/src/cmd/sgs/libld/common/args.c index 3823c51bb1..0d18215a68 100644 --- a/usr/src/cmd/sgs/libld/common/args.c +++ b/usr/src/cmd/sgs/libld/common/args.c @@ -833,6 +833,7 @@ createargv(Ofl_desc *ofl, int *error) return (ret); } +static int optitle = 0; /* * Parsing options pass1 for process_flags(). */ @@ -855,7 +856,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) switch (c) { case '6': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * -64 is processed by ld to determine the output class. @@ -871,12 +872,12 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) continue; case 'a': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); aflag = TRUE; break; case 'b': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); bflag = TRUE; /* @@ -893,7 +894,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'c': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_config) eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_ARG_MTONCE), @@ -903,12 +904,12 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'C': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); demangle_flag = 1; break; case 'd': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if ((optarg[0] == 'n') && (optarg[1] == '\0')) { if (dflag != SET_UNKNOWN) eprintf(ofl->ofl_lml, ERR_WARNING, @@ -932,7 +933,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'e': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_entry) eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MARG_MTONCE), @@ -942,7 +943,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'f': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_filtees && (!(ofl->ofl_flags & FLG_OF_AUX))) { eprintf(ofl->ofl_lml, ERR_FATAL, @@ -960,7 +961,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'F': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_filtees && (ofl->ofl_flags & FLG_OF_AUX)) { eprintf(ofl->ofl_lml, ERR_FATAL, @@ -977,7 +978,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'h': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_soname) eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MARG_MTONCE), @@ -987,12 +988,12 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'i': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); ofl->ofl_flags |= FLG_OF_IGNENV; break; case 'I': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_interp) eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_ARG_MTONCE), @@ -1002,7 +1003,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'l': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * For now, count any library as a shared object. This * is used to size the internal symbol cache. This @@ -1013,12 +1014,12 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'm': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); ofl->ofl_flags |= FLG_OF_GENMAP; break; case 'o': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ofl->ofl_name) eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MARG_MTONCE), @@ -1028,7 +1029,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'p': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * Multiple instances of this option may occur. Each @@ -1044,7 +1045,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'P': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * Multiple instances of this option may occur. Each @@ -1060,12 +1061,12 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'r': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); rflag = TRUE; break; case 'R': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * Multiple instances of this option may occur. Each @@ -1081,21 +1082,21 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 's': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); sflag = TRUE; break; case 't': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); ofl->ofl_flags |= FLG_OF_NOWARN; break; case 'u': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); break; case 'z': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * For specific help, print our usage message and exit @@ -1343,12 +1344,18 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) /* * A diagnostic can only be provided after dbg_setup(). + * As this is the first diagnostic that can be produced + * by ld(1), issue a title for timing and basic output. */ - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + if ((optitle == 0) && DBG_ENABLED) { + optitle++; + DBG_CALL(Dbg_basic_options(ofl->ofl_lml)); + } + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); break; case 'B': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (strcmp(optarg, MSG_ORIG(MSG_ARG_DIRECT)) == 0) { if (Bdflag == SET_FALSE) { eprintf(ofl->ofl_lml, ERR_FATAL, @@ -1393,27 +1400,27 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'G': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); Gflag = TRUE; break; case 'L': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); break; case 'M': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (aplist_append(&(ofl->ofl_maps), optarg, AL_CNT_OFL_MAPFILES) == NULL) return (S_ERROR); break; case 'N': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); break; case 'Q': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if ((optarg[0] == 'n') && (optarg[1] == '\0')) { if (Qflag != SET_UNKNOWN) eprintf(ofl->ofl_lml, ERR_WARNING, @@ -1437,14 +1444,14 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'S': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (aplist_append(&lib_support, optarg, AL_CNT_SUPPORT) == NULL) return (S_ERROR); break; case 'V': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); if (!Vflag) (void) fprintf(stderr, MSG_ORIG(MSG_STR_STRNL), ofl->ofl_sgsid); @@ -1452,7 +1459,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case 'Y': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, optarg)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (strncmp(optarg, MSG_ORIG(MSG_ARG_LCOM), 2) == 0) { if (Llibdir) eprintf(ofl->ofl_lml, ERR_WARNING, @@ -1485,7 +1492,7 @@ parseopt_pass1(Ofl_desc *ofl, int argc, char **argv, int *error) break; case '?': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, NULL)); + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, NULL)); (*error)++; break; @@ -1515,13 +1522,13 @@ parseopt_pass2(Ofl_desc *ofl, int argc, char **argv) switch (c) { case 'l': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ld_find_library(optarg, ofl) == S_ERROR) return (S_ERROR); break; case 'B': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (strcmp(optarg, MSG_ORIG(MSG_STR_LD_DYNAMIC)) == 0) { @@ -1539,13 +1546,13 @@ parseopt_pass2(Ofl_desc *ofl, int argc, char **argv) ofl->ofl_flags &= ~FLG_OF_DYNLIBS; break; case 'L': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ld_add_libdir(ofl, optarg) == S_ERROR) return (S_ERROR); break; case 'N': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); /* * Record DT_NEEDED string @@ -1569,19 +1576,19 @@ parseopt_pass2(Ofl_desc *ofl, int argc, char **argv) break; case 'D': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); (void) dbg_setup(ofl, optarg, 3); break; case 'u': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if (ld_sym_add_u(optarg, ofl, MSG_STR_COMMAND) == (Sym_desc *)S_ERROR) return (S_ERROR); break; case 'z': - DBG_CALL(Dbg_args_opts(ofl->ofl_lml, ndx, c, + DBG_CALL(Dbg_args_option(ofl->ofl_lml, ndx, c, optarg)); if ((strncmp(optarg, MSG_ORIG(MSG_ARG_LD32), MSG_ARG_LD32_SIZE) == 0) || @@ -1808,7 +1815,7 @@ process_files_com(Ofl_desc *ofl, int argc, char **argv) continue; } - DBG_CALL(Dbg_args_files(ofl->ofl_lml, optind, path)); + DBG_CALL(Dbg_args_file(ofl->ofl_lml, optind, path)); ifl = ld_process_open(path, path, &fd, ofl, (FLG_IF_CMDLINE | FLG_IF_NEEDED), &rej); @@ -1839,9 +1846,11 @@ process_files_com(Ofl_desc *ofl, int argc, char **argv) uintptr_t ld_process_files(Ofl_desc *ofl, int argc, char **argv) { + DBG_CALL(Dbg_basic_files(ofl->ofl_lml)); + /* * Process command line files (taking into account any applicable - * preceeding flags). Return if any fatal errors have occurred. + * preceding flags). Return if any fatal errors have occurred. */ opterr = 0; optind = 1; diff --git a/usr/src/cmd/sgs/libld/common/debug.c b/usr/src/cmd/sgs/libld/common/debug.c index 4ffa5ef19f..127a921987 100644 --- a/usr/src/cmd/sgs/libld/common/debug.c +++ b/usr/src/cmd/sgs/libld/common/debug.c @@ -30,6 +30,7 @@ #include <strings.h> #include <dlfcn.h> #include <debug.h> +#include <conv.h> #include "msg.h" /* @@ -205,6 +206,22 @@ dbg_print(Lm_list *lml, const char *format, ...) } else (void) fputs(MSG_INTL(MSG_DBG_DFLT_FMT), dbg_ofile.fptr); + if (DBG_ISTIME()) { + Conv_time_buf_t buf; + struct timeval new; + + if (gettimeofday(&new, NULL) == 0) { + if (DBG_ISTTIME()) + (void) fputs(conv_time(&DBG_TOTALTIME, &new, + &buf), stderr); + if (DBG_ISDTIME()) + (void) fputs(conv_time(&DBG_DELTATIME, &new, + &buf), stderr); + + DBG_DELTATIME = new; + } + } + va_start(args, format); (void) vfprintf(dbg_ofile.fptr, format, args); (void) fprintf(dbg_ofile.fptr, MSG_ORIG(MSG_STR_NL)); diff --git a/usr/src/cmd/sgs/libld/common/ldmain.c b/usr/src/cmd/sgs/libld/common/ldmain.c index 19ef992801..4c850ec780 100644 --- a/usr/src/cmd/sgs/libld/common/ldmain.c +++ b/usr/src/cmd/sgs/libld/common/ldmain.c @@ -35,6 +35,7 @@ * ld -- link/editor main program */ #include <sys/types.h> +#include <sys/time.h> #include <sys/mman.h> #include <string.h> #include <stdio.h> @@ -114,6 +115,13 @@ ld_main(int argc, char **argv, Half mach) Ofl_desc *ofl; /* + * Establish a base time. Total time diagnostics are relative to + * entering the link-editor here. + */ + (void) gettimeofday(&DBG_TOTALTIME, NULL); + DBG_DELTATIME = DBG_TOTALTIME; + + /* * Initialize signal handlers, and output file variables. Establish a * default output ELF header to satisfy diagnostic requirements. */ @@ -186,10 +194,10 @@ ld_main(int argc, char **argv, Half mach) do { if (ld_sup_loadso(ofl, lib) == S_ERROR) return (ld_exit(ofl)); + DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD)); } while ((lib = strtok_r(NULL, sep, &lasts)) != NULL); } - DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD)); } if (lib_support) { Aliste idx; @@ -200,9 +208,9 @@ ld_main(int argc, char **argv, Half mach) DBG_SUP_CMDLINE)); if (ld_sup_loadso(ofl, lib) == S_ERROR) return (ld_exit(ofl)); + DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD)); } } - DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD)); DBG_CALL(Dbg_ent_print(ofl->ofl_lml, ofl->ofl_dehdr->e_ident[EI_OSABI], ofl->ofl_dehdr->e_machine, @@ -383,6 +391,7 @@ ld_main(int argc, char **argv, Half mach) ld_sup_atexit(ofl, 0); DBG_CALL(Dbg_statistics_ld(ofl)); + DBG_CALL(Dbg_basic_finish(ofl->ofl_lml)); /* * Wrap up debug output file if one is open diff --git a/usr/src/cmd/sgs/libld/common/outfile.c b/usr/src/cmd/sgs/libld/common/outfile.c index 8c51c8e1ef..ba81305a91 100644 --- a/usr/src/cmd/sgs/libld/common/outfile.c +++ b/usr/src/cmd/sgs/libld/common/outfile.c @@ -377,6 +377,8 @@ ld_create_outfile(Ofl_desc *ofl) Boolean fixalign = FALSE; int fd, nseg = 0, shidx, dataidx, ptloadidx = 0; + DBG_CALL(Dbg_basic_create(ofl->ofl_lml)); + /* * If DF_1_NOHDR was set in map_parse() or FLG_OF1_VADDR was set, * we need to do alignment adjustment. diff --git a/usr/src/cmd/sgs/libld/common/relocate.c b/usr/src/cmd/sgs/libld/common/relocate.c index 2f31d506b1..307f7ef426 100644 --- a/usr/src/cmd/sgs/libld/common/relocate.c +++ b/usr/src/cmd/sgs/libld/common/relocate.c @@ -2138,6 +2138,8 @@ ld_reloc_init(Ofl_desc *ofl) Is_desc *isp; Sym_desc *sdp; + DBG_CALL(Dbg_basic_collect(ofl->ofl_lml)); + /* * At this point we have finished processing all input symbols. Make * sure we add any absolute (internal) symbols before continuing with @@ -2381,6 +2383,8 @@ ld_reloc_process(Ofl_desc *ofl) ofl_flag_t flags = ofl->ofl_flags; Shdr *shdr; + DBG_CALL(Dbg_basic_relocate(ofl->ofl_lml)); + /* * Determine the index of the symbol table that will be referenced by * the relocation entries. diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c index 6638dac5e6..38b960bc7d 100644 --- a/usr/src/cmd/sgs/libld/common/syms.c +++ b/usr/src/cmd/sgs/libld/common/syms.c @@ -1091,6 +1091,8 @@ ld_sym_validate(Ofl_desc *ofl) int allow_ldynsym; uchar_t type; + DBG_CALL(Dbg_basic_validate(ofl->ofl_lml)); + /* * If a symbol is undefined and this link-edit calls for no undefined * symbols to remain (this is the default case when generating an diff --git a/usr/src/cmd/sgs/liblddbg/Makefile.com b/usr/src/cmd/sgs/liblddbg/Makefile.com index b7e2980d05..339d8b9537 100644 --- a/usr/src/cmd/sgs/liblddbg/Makefile.com +++ b/usr/src/cmd/sgs/liblddbg/Makefile.com @@ -19,17 +19,15 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# LIBRARY = liblddbg.a VERS = .4 -COMOBJS = args.o audit.o debug.o syminfo.o \ - tls.o +COMOBJS = args.o audit.o basic.o debug.o \ + syminfo.o tls.o COMOBJS32 = bindings32.o cap32.o dynamic32.o elf32.o \ entry32.o files32.o got32.o libs32.o \ diff --git a/usr/src/cmd/sgs/liblddbg/common/args.c b/usr/src/cmd/sgs/liblddbg/common/args.c index e210f32e7b..4b56f4887f 100644 --- a/usr/src/cmd/sgs/liblddbg/common/args.c +++ b/usr/src/cmd/sgs/liblddbg/common/args.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,7 +29,7 @@ #include "msg.h" void -Dbg_args_opts(Lm_list *lml, int ndx, int c, char *optarg) +Dbg_args_option(Lm_list *lml, int ndx, int c, char *optarg) { if (DBG_NOTCLASS(DBG_C_ARGS)) return; @@ -59,7 +59,7 @@ Dbg_args_Wldel(Lm_list *lml, int ndx, const char *opt) } void -Dbg_args_files(Lm_list *lml, int ndx, char *file) +Dbg_args_file(Lm_list *lml, int ndx, char *file) { if (DBG_NOTCLASS(DBG_C_ARGS)) return; diff --git a/usr/src/cmd/sgs/liblddbg/common/basic.c b/usr/src/cmd/sgs/liblddbg/common/basic.c new file mode 100644 index 0000000000..fd66f8af99 --- /dev/null +++ b/usr/src/cmd/sgs/liblddbg/common/basic.c @@ -0,0 +1,111 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <debug.h> +#include "_debug.h" +#include "msg.h" + +/* + * This file contains a number of simple title interfaces, that give a basic + * trace of a link-edit. These interfaces cross several functional boundaries, + * but are consolidated here to ensure consistent use of the DBG_C_BASIC and + * DBG_NOTTIME macros. + */ +void +Dbg_basic_collect(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_COLLECT)); + Dbg_util_nl(lml, DBG_NL_STD); +} + +void +Dbg_basic_create(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_CREATE)); + Dbg_util_nl(lml, DBG_NL_STD); +} + +void +Dbg_basic_files(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_FILES)); + Dbg_util_nl(lml, DBG_NL_STD); +} +void +Dbg_basic_finish(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_FINISHED)); + Dbg_util_nl(lml, DBG_NL_STD); +} + +void +Dbg_basic_options(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_OPTIONS)); + Dbg_util_nl(lml, DBG_NL_STD); +} + +void +Dbg_basic_relocate(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_RELOCATE)); + Dbg_util_nl(lml, DBG_NL_STD); +} + +void +Dbg_basic_validate(Lm_list *lml) +{ + if (DBG_NOTCLASS(DBG_C_BASIC) && DBG_NOTTIME()) + return; + + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_BASIC_VALIDATE)); + Dbg_util_nl(lml, DBG_NL_STD); +} diff --git a/usr/src/cmd/sgs/liblddbg/common/debug.c b/usr/src/cmd/sgs/liblddbg/common/debug.c index 110d64938a..7026a6ac80 100644 --- a/usr/src/cmd/sgs/liblddbg/common/debug.c +++ b/usr/src/cmd/sgs/liblddbg/common/debug.c @@ -39,7 +39,7 @@ * definition to which most users bind, ld.so.1 must provide its own definition, * and thus interposition is expected. This item should be defined NODIRECT. */ -static Dbg_desc _dbg_desc = { 0, 0, 0 }; +static Dbg_desc _dbg_desc = { 0, 0, NULL, { 0, 0 }, { 0, 0 } }; Dbg_desc *dbg_desc = &_dbg_desc; int _Dbg_cnt = 0; @@ -54,6 +54,8 @@ static DBG_options _Dbg_options[] = { /* Options accepted by both linkers */ {MSG_ORIG(MSG_TOK_DETAIL), 0, DBG_E_DETAIL}, {MSG_ORIG(MSG_TOK_LONG), 0, DBG_E_LONG}, {MSG_ORIG(MSG_TOK_HELP), 0, DBG_E_HELP}, + {MSG_ORIG(MSG_TOK_TTIME), 0, DBG_E_TTIME}, + {MSG_ORIG(MSG_TOK_DTIME), 0, DBG_E_DTIME}, {MSG_ORIG(MSG_TOK_ALL), DBG_C_ALL, 0}, {MSG_ORIG(MSG_TOK_BASIC), DBG_C_BASIC, 0}, @@ -193,9 +195,18 @@ Dbg_help(void) dbg_print(0, MSG_INTL(MSG_USE_R4_B)); dbg_print(0, MSG_INTL(MSG_USE_R4_B2)); dbg_print(0, MSG_INTL(MSG_USE_R4_C)); + dbg_print(0, MSG_INTL(MSG_USE_R4_C2)); + dbg_print(0, MSG_INTL(MSG_USE_R4_C3)); dbg_print(0, MSG_INTL(MSG_USE_R4_D)); - dbg_print(0, MSG_INTL(MSG_USE_R4_D2)); - dbg_print(0, MSG_INTL(MSG_USE_R4_D3)); + dbg_print(0, MSG_INTL(MSG_USE_R4_E)); + dbg_print(0, MSG_INTL(MSG_USE_R4_E2)); + dbg_print(0, MSG_INTL(MSG_USE_R4_E3)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F2)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F3)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F4)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F5)); + dbg_print(0, MSG_INTL(MSG_USE_R4_F6)); Dbg_util_nl(0, DBG_NL_FRC); dbg_print(0, MSG_INTL(MSG_USE_HDR_RTLD)); diff --git a/usr/src/cmd/sgs/liblddbg/common/files.c b/usr/src/cmd/sgs/liblddbg/common/files.c index b4fbd54845..e529e2f0f6 100644 --- a/usr/src/cmd/sgs/liblddbg/common/files.c +++ b/usr/src/cmd/sgs/liblddbg/common/files.c @@ -245,6 +245,7 @@ Dbg_file_hdl_action(Grp_hdl *ghp, Rt_map *lmp, int type, uint_t flags) if (hdl_title) { Dbg_util_nl(lml, DBG_NL_STD); if (hdl_str) { + Conv_grphdl_flags_buf_t grphdl_flags_buf; const char *name; /* @@ -256,7 +257,9 @@ Dbg_file_hdl_action(Grp_hdl *ghp, Rt_map *lmp, int type, uint_t flags) else name = MSG_INTL(MSG_STR_UNKNOWN); - dbg_print(lml, MSG_INTL(hdl_str), name, EC_NATPTR(ghp)); + dbg_print(lml, MSG_INTL(hdl_str), name, + conv_grphdl_flags(ghp->gh_flags, &grphdl_flags_buf), + EC_NATPTR(ghp)); } hdl_title = 0; } diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg index 558e1a3c28..a2e64315ac 100644 --- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg @@ -216,10 +216,19 @@ # demangle show C++ symbol names in their demangled form # detail provide more information in conjunction with # other options +# dtime prepend a time delta to diagnostics. The value +# appears as seconds.fraction, and represents +# the elapsed time since that last diagnostic. # long display long object names without truncation # output=file debug output is sent to the named file # instead of stderr. If file is empty (\"\"), # following output will be sent to stderr. +# ttime prepend a time stamp to diagnostics. The value +# appears as seconds.fraction, and represents +# the time since entering ld or ld.so.1. +# Note, all diagnostics induce a probe affect, +# which should be taken into account when +# interpreting dtime and ttime information. # # TRANSLATION_NOTE - The next series of messages makes the above output in C @@ -234,24 +243,46 @@ conjunction with" @ MSG_USE_R4_B2 " other options" +# TRANSLATION_NOTE -- do not translate the first token "dtime". +@ MSG_USE_R4_C " dtime prepend a time delta to diagnostics. \ + The value" +@ MSG_USE_R4_C2 " appears as seconds.fraction, and \ + represents" +@ MSG_USE_R4_C3 " the elapsed time since that last \ + diagnostic." + # TRANSLATION_NOTE -- do not translate the first token "long". -@ MSG_USE_R4_C " long display long object names without \ +@ MSG_USE_R4_D " long display long object names without \ truncation" # TRANSLATION_NOTE -- do not translate the first token "output". -@ MSG_USE_R4_D " output=file debug output is sent to the \ +@ MSG_USE_R4_E " output=file debug output is sent to the \ named file" -@ MSG_USE_R4_D2 " instead of stderr. If file is \ +@ MSG_USE_R4_E2 " instead of stderr. If file is \ empty (\"\")," -@ MSG_USE_R4_D3 " following output will be \ +@ MSG_USE_R4_E3 " following output will be \ sent to stderr." +# TRANSLATION_NOTE -- do not translate the first token "ttime". +@ MSG_USE_R4_F " ttime prepend a time stamp to diagnostics. \ + The value" +@ MSG_USE_R4_F2 " appears as seconds.fraction, and \ + represents" +@ MSG_USE_R4_F3 " the time since entering ld or \ + ld.so.1." +@ MSG_USE_R4_F4 " Note all diagnostics induce a \ + probe affect," +@ MSG_USE_R4_F5 " which should be taken into \ + account when" +@ MSG_USE_R4_F6 " interpreting dtime and ttime \ + information." + # TRANSLATION_NOTE - End of reference 4 # TRANSLATION_NOTE - Use the following output in the C locale as reference 5. # -# lmid[=name] Prepend link-map list id to diagnostics, and +# lmid[=name] prepend link-map list id to diagnostics, and # optionally filter the lists: By default, # diagnostics are produced for all link-map # lists except that of the runtime linker @@ -273,7 +304,7 @@ # TRANSLATION_NOTE -- do not translate the first token "lmid". -@ MSG_USE_R5_A " lmid[=name] Prepend link-map list id to \ +@ MSG_USE_R5_A " lmid[=name] prepend link-map list id to \ diagnostics, and" @ MSG_USE_R5_A2 " optionally filter the lists: By \ default," @@ -490,6 +521,16 @@ # TRANSLATION_NOTE - End of reference 9 +# Basic processing (ld). + +@ MSG_BASIC_COLLECT "collect relocations" +@ MSG_BASIC_CREATE "create output image" +@ MSG_BASIC_FILES "process files" +@ MSG_BASIC_FINISHED "processing finished" +@ MSG_BASIC_OPTIONS "process options" +@ MSG_BASIC_RELOCATE "relocate output image" +@ MSG_BASIC_VALIDATE "validating symbols" + # Argument messages @ MSG_ARG_OPTION "arg[%d]\toption=-%c" @@ -638,8 +679,8 @@ @ MSG_FIL_DEP_ORPHAN " file=%s; object remains on orphan handle %s" @ MSG_FIL_DEP_REINST " file=%s; object reinstated %s" -@ MSG_FIL_HDL_CREATE "handle=%s; creating: 0x%llx" -@ MSG_FIL_HDL_ADD "handle=%s; adding dependent objects:" +@ MSG_FIL_HDL_CREATE "handle=%s; creating %s 0x%llx:" +@ MSG_FIL_HDL_ADD "handle=%s; adding dependent objects %s:" @ MSG_FIL_HDL_DELETE "handle=%s; inspecting for deletion:" @ MSG_FIL_HDL_ORPHAN "handle=%s; deletion cannot be completed: moving to \ orphan list:" @@ -1352,6 +1393,9 @@ @ MSG_TOK_FULLNAME "fullname" @ MSG_TOK_CLASS "class" @ MSG_TOK_LMID "lmid" +@ MSG_TOK_TTIME "ttime" +@ MSG_TOK_DTIME "dtime" + @ MSG_TOK_OUTFILE "output" @ MSG_TOK_LMID_ALL "ALL" diff --git a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg index 98d4ccaef6..56648cadc6 100644 --- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg +++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg @@ -15,7 +15,7 @@ * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] - * + * CDDL HEADER END */ /* LINTLIBRARY */ @@ -34,8 +34,8 @@ int Dbg_setup(dbg_setup_caller_t, const char *, Dbg_desc *, const char **); const char * Dbg_demangle_name(const char *); -void Dbg_args_files(Lm_list *, int, char *); -void Dbg_args_opts(Lm_list *, int, int, char *); +void Dbg_args_file(Lm_list *, int, char *); +void Dbg_args_option(Lm_list *, int, int, char *); void Dbg_args_str2chr(Lm_list *, int, const char *, int); void Dbg_args_Wldel(Lm_list *, int, const char *); void Dbg_audit_ignore(Rt_map *); @@ -48,6 +48,14 @@ void Dbg_audit_skip(Lm_list *, const char *, const char *); void Dbg_audit_terminate(Lm_list *, const char *); void Dbg_audit_version(Lm_list *, const char *, ulong_t); +void Dbg_basic_collect(Lm_list *); +void Dbg_basic_create(Lm_list *); +void Dbg_basic_files(Lm_list *); +void Dbg_basic_finish(Lm_list *); +void Dbg_basic_options(Lm_list *); +void Dbg_basic_relocate(Lm_list *); +void Dbg_basic_validate(Lm_list *); + void Dbg_tls_modactivity(Lm_list *, void *, uint_t); void Dbg_tls_static_block(Lm_list *, void *, ulong_t, ulong_t); void Dbg_tls_static_resv(Rt_map *, ulong_t, ulong_t); diff --git a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers index dc6b90c4f2..2dba0119b0 100644 --- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers +++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers @@ -41,13 +41,13 @@ # MAPFILE HEADER END # -SUNWprivate_4.71 { +SUNWprivate_4.72 { global: dbg_desc = NODIRECT; # interposed - ld.so.1(1) dbg_print = NODIRECT; # interposed - ld(1) and ld.so.1(1) - Dbg_args_files; - Dbg_args_opts; + Dbg_args_file; + Dbg_args_option; Dbg_args_str2chr; Dbg_args_Wldel; Dbg_audit_ignore; @@ -59,6 +59,14 @@ SUNWprivate_4.71 { Dbg_audit_terminate; Dbg_audit_version; + Dbg_basic_collect; + Dbg_basic_create; + Dbg_basic_files; + Dbg_basic_finish; + Dbg_basic_options; + Dbg_basic_relocate; + Dbg_basic_validate; + Dbg_help; Dbg_setup; diff --git a/usr/src/cmd/sgs/packages/Makefile.targ b/usr/src/cmd/sgs/packages/Makefile.targ index d32d41e1c7..27f0ce4ea1 100644 --- a/usr/src/cmd/sgs/packages/Makefile.targ +++ b/usr/src/cmd/sgs/packages/Makefile.targ @@ -18,10 +18,7 @@ # # CDDL HEADER END # -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. pkginfo: ../common/pkginfo.tmpl awk_pkginfo @@ -29,7 +26,7 @@ pkginfo: ../common/pkginfo.tmpl awk_pkginfo pkg: FRC @ $(RM) -r $(PACKAGE) - pkgmk -l 20000 -f prototype_$(MACH) -d $(PKGARCHIVE) -r $(ROOT) \ + pkgmk -f prototype_$(MACH) -d $(PKGARCHIVE) -r $(ROOT) \ -o $(PACKAGE) 2>&1 | egrep -v "$(SRC)|parametric paths may" pkgtrans -o -s $(PKGARCHIVE) $(PACKAGE).tmp $(PACKAGE) $(RM) -r $(PKGARCHIVE)/$(PACKAGE) diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README index b46a2806c5..6e023b14cf 100644 --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README @@ -1254,6 +1254,7 @@ Bugid Risk Synopsis 6805502 The addition of "inline" keywords to sgs code broke the lint verification in S10 6807864 ld.so.1 is susceptible to a fatal dlsym()/setlocale() race +6826410 ld needs to sort sections using 32-bit sort keys -------------------------------------------------------------------------------- All the above changes are incorporated in the following patches: Solaris/SunOS 5.10_sparc patch TXXXXXX-XX @@ -1478,3 +1479,4 @@ Bugid Risk Synopsis 6806791 filter builds could be optimized (link-editor components only) 6823371 calloc() uses suboptimal memset() causing 15% regression in SpecCPU2006 gcc code (link-editor components only) +6831308 ld.so.1: symbol rescanning does a little too much work diff --git a/usr/src/cmd/sgs/rtld/common/_elf.h b/usr/src/cmd/sgs/rtld/common/_elf.h index 6babcb8c78..0e010fab08 100644 --- a/usr/src/cmd/sgs/rtld/common/_elf.h +++ b/usr/src/cmd/sgs/rtld/common/_elf.h @@ -53,7 +53,7 @@ extern int elf_copy_reloc(char *, Sym *, Rt_map *, void *, Sym *, extern Sym *elf_find_sym(Slookup *, Rt_map **, uint_t *, int *); extern Sym *elf_lazy_find_sym(Slookup *, Rt_map **, uint_t *, int *); extern Rt_map *elf_lazy_load(Rt_map *, Slookup *, uint_t, const char *, - int *); + uint_t, Grp_hdl **, int *); extern Sym *elf_lookup_filtee(Slookup *, Rt_map **, uint_t *, uint_t, int *); extern int elf_mach_flags_check(Rej_desc *, Ehdr *); diff --git a/usr/src/cmd/sgs/rtld/common/_rtld.h b/usr/src/cmd/sgs/rtld/common/_rtld.h index aa3355ffa0..2dad943572 100644 --- a/usr/src/cmd/sgs/rtld/common/_rtld.h +++ b/usr/src/cmd/sgs/rtld/common/_rtld.h @@ -138,7 +138,7 @@ struct fct { #define AL_CNT_ALIAS 2 /* ALIAS() */ #define AL_CNT_DEPENDS 20 /* DEPENDS() */ #define AL_CNT_CALLERS 20 /* CALLERS() */ -#define AL_CNT_GROUPS 4 /* GROUPS() */ +#define AL_CNT_GROUPS 20 /* GROUPS() */ #define AL_CNT_COPYREL 10 /* COPY() */ #define AL_CNT_LAZYFIND 10 /* elf_lazy_find_sym() */ #define AL_CNT_GRPCLCT 10 /* gdp_collect() */ @@ -567,7 +567,7 @@ extern APlist *free_alp; /* defragmentation list */ extern uint_t audit_argcnt; /* no. of stack args to copy */ extern Audit_desc *auditors; /* global auditors */ -extern char **_environ; +extern char **_environ; /* environ reference for libc */ extern const char *dbg_file; /* debugging directed to a file */ @@ -629,7 +629,7 @@ extern uint_t expand(char **, size_t *, char **, uint_t, uint_t, Rt_map *); extern int expand_paths(Rt_map *, const char *, Alist **, Aliste, uint_t, uint_t); -extern void free_hdl(Grp_hdl *, Rt_map *, uint_t); +extern void free_hdl(Grp_hdl *); extern void file_notfound(Lm_list *, const char *, Rt_map *, uint_t, Rej_desc *); extern int find_path(Lm_list *, Rt_map *, uint_t, Fdesc *, @@ -642,7 +642,7 @@ extern void fpavl_remove(Rt_map *); extern size_t fullpath(Rt_map *, Fdesc *); extern Lmid_t get_linkmap_id(Lm_list *); extern Pdesc *get_next_dir(Spath_desc *, Rt_map *, uint_t); -extern int hdl_add(Grp_hdl *, Rt_map *, uint_t); +extern Grp_desc *hdl_add(Grp_hdl *, Rt_map *, uint_t, int *); extern Grp_hdl *hdl_create(Lm_list *, Rt_map *, Rt_map *, uint_t, uint_t, uint_t); extern int hdl_initialize(Grp_hdl *, Rt_map *, int, int); diff --git a/usr/src/cmd/sgs/rtld/common/analyze.c b/usr/src/cmd/sgs/rtld/common/analyze.c index 09400a8940..4afa82c9c3 100644 --- a/usr/src/cmd/sgs/rtld/common/analyze.c +++ b/usr/src/cmd/sgs/rtld/common/analyze.c @@ -447,7 +447,7 @@ _relocate_lmc(Lm_list *lml, Aliste lmco, Rt_map *nlmp, int *relocated, DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD)); free(COPY_S(nlmp)); - COPY_S(nlmp) = 0; + COPY_S(nlmp) = NULL; } return (1); } @@ -689,17 +689,24 @@ _is_so_matched(const char *name, const char *str, int path) * Determine whether a search name matches one of the names associated with a * link-map. A link-map contains several names: * - * . a NAME() - typically the full pathname of an object that has been - * loaded. For example, when looking for the dependency "libc.so.1", a - * search path is applied, with the eventual NAME() being "/lib/libc.so.1". - * The name of a dynamic executable can be a simple filename, such as - * "main", as this can be the name passed to exec() to start the process. + * - a NAME() - this is the basename of the dynamic executable that started + * the process, and the path name of any dependencies used by the process. + * Most executables are received as full path names, as exec() prepends a + * search $PATH to locate the executable. However, simple file names can + * be received from exec() if the file is executed from the present working + * directory. Regardless, ld.so.1 maintains NAME() as the basename, as + * this has always been the name used in diagnostics and error messages. + * Most dependencies are full path names, as the typical search for a + * dependency, say "libx.so.1", results in search paths being prepended to + * the name, which eventually open "/lib/libx.so.1". However, relative + * path names can be supplied as dependencies, e.g. dlopen("../libx.so.1"). * - * . a PATHNAME() - this is maintained if the resolved NAME() is different - * than NAME(), ie. a component of the original name is a symbolic link. - * This is also the resolved full pathname for a simple dynamic executable. + * - a PATHNAME() - this is the fully resolved path name of the object. This + * name will differ from NAME() for all dynamic executables, and may differ + * from the NAME() of dependencies, if the dependency is not a full path + * name, or the dependency resolves to a symbolic link. * - * . an ALIAS() name - these are alternative names by which the object has + * - an ALIAS() name - these are alternative names by which the object has * been found, ie. when dependencies are loaded through a variety of * different symbolic links. * @@ -739,12 +746,12 @@ is_so_matched(Rt_map *lmp, const char *name, int path) * environment. Once a full path name has been established, the following * checks are made: * - * . does the path exist in the link-map lists FullPathNode AVL tree? if + * - does the path exist in the link-map lists FullPathNode AVL tree? if * so, the file is already loaded, and its associated link-map pointer * is returned. - * . does the path exist in the not-found AVL tree? if so, this path has + * - does the path exist in the not-found AVL tree? if so, this path has * already been determined to not exist, and a failure is returned. - * . a device/inode check, to ensure the same file isn't mapped multiple + * - a device/inode check, to ensure the same file isn't mapped multiple * times through different paths. See file_open(). * * However, there are cases where a test for an existing file name needs to be @@ -2147,12 +2154,13 @@ static int load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, uint_t flags, Grp_hdl **hdl, Rt_map *nlmp) { - Aliste idx; + Aliste idx1; Grp_hdl *ghp; int promote; + uint_t rdflags; /* - * If this dependency is associated with a required version insure that + * If this dependency is associated with a required version ensure that * the version is present in the loaded file. */ if (((rtld_flags & RT_FL_NOVERSION) == 0) && THIS_IS_ELF(clmp) && @@ -2163,25 +2171,27 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, * If this object has indicated that it should be isolated as a group * (DT_FLAGS_1 contains DF_1_GROUP - object was built with -B group), * or if the callers direct bindings indicate it should be isolated as - * a group (DYNINFO flags contains FLG_DI_GROUP - dependency followed + * a group (DYNINFO flags contains FLG_DI_GROUP - dependency following * -zgroupperm), establish the appropriate mode. * * The intent of an object defining itself as a group is to isolate the * relocation of the group within its own members, however, unless * opened through dlopen(), in which case we assume dlsym() will be used - * to located symbols in the new object, we still need to associate it - * with the caller for it to be bound with. This is equivalent to a - * dlopen(RTLD_GROUP) and dlsym() using the returned handle. + * to locate symbols in the new object, we still need to associate the + * new object with the caller so that the caller can bind to this new + * object. This is equivalent to a dlopen(RTLD_GROUP) and dlsym() + * using the returned handle. */ if ((FLAGS(nlmp) | flags) & FLG_RT_SETGROUP) { nmode &= ~RTLD_WORLD; nmode |= RTLD_GROUP; /* - * If the object wasn't explicitly dlopen()'ed associate it with + * If the object wasn't explicitly dlopen()'ed, in which case a + * handle would have been requested, associate the object with * the parent. */ - if ((flags & FLG_RT_HANDLE) == 0) + if ((flags & FLG_RT_PUBHDL) == 0) nmode |= RTLD_PARENT; } @@ -2192,6 +2202,17 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, FLAGS(nlmp) |= flags; /* + * Establish the flags for any referenced dependency descriptors + * (Grp_desc). + * + * - The referenced object is available for dlsym(). + * - The referenced object is available to relocate against. + * - The referenced object should have it's dependencies + * added to this handle + */ + rdflags = (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS); + + /* * If this is a global object, ensure the associated link-map list can * be rescanned for global, lazy dependencies. */ @@ -2201,59 +2222,83 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, /* * If we've been asked to establish a handle create one for this object. * Or, if this object has already been analyzed, but this reference - * requires that the mode of the object be promoted, also create a + * requires that the mode of the object be promoted, create a private * handle to propagate the new modes to all this objects dependencies. */ - if (((FLAGS(nlmp) | flags) & FLG_RT_HANDLE) || (promote && - (FLAGS(nlmp) & FLG_RT_ANALYZED))) { - uint_t oflags, hflags = 0, cdflags; + if ((FLAGS(nlmp) & (FLG_RT_PUBHDL | FLG_RT_PRIHDL)) || + (promote && (FLAGS(nlmp) & FLG_RT_ANALYZED))) { + uint_t oflags, hflags, cdflags = 0; /* * Establish any flags for the handle (Grp_hdl). * - * . Use of the RTLD_FIRST flag indicates that only the first + * - Public handles establish dependencies between objects + * that must be taken into account when dlclose()'ing + * objects. Private handles provide for collecting + * dependencies, but do not affect dlclose(). Note that + * a handle may already exist, but the public/private + * state is set to trigger the required propagation of the + * handle's flags and any dependency gathering. + * - Use of the RTLD_FIRST flag indicates that only the first * dependency on the handle (the new object) can be used * to satisfy dlsym() requests. */ + if (FLAGS(nlmp) & FLG_RT_PUBHDL) + hflags = GPH_PUBLIC; + else + hflags = GPH_PRIVATE; + if (nmode & RTLD_FIRST) - hflags = GPH_FIRST; + hflags |= GPH_FIRST; /* * Establish the flags for this callers dependency descriptor * (Grp_desc). * - * . The creation of a handle associates a descriptor for the - * new object and descriptor for the parent (caller). + * - The creation of a public handle creates a descriptor + * for the referenced object and the caller (parent). * Typically, the handle is created for dlopen() or for - * filtering. A handle may also be created to promote - * the callers modes (RTLD_NOW) to the new object. In this - * latter case, the handle/descriptor are torn down once - * the mode propagation has occurred. - * - * . Use of the RTLD_PARENT flag indicates that the parent + * filtering. A private handle does not need to maintain + * a descriptor to the parent. + * - Use of the RTLD_PARENT flag indicates that the parent * can be relocated against. */ - if (((FLAGS(nlmp) | flags) & FLG_RT_HANDLE) == 0) - cdflags = GPD_PROMOTE; - else - cdflags = GPD_PARENT; - if (nmode & RTLD_PARENT) - cdflags |= GPD_RELOC; + if (FLAGS(nlmp) & FLG_RT_PUBHDL) { + cdflags |= GPD_PARENT; + if (nmode & RTLD_PARENT) + cdflags |= GPD_RELOC; + } /* - * Now that a handle is being created, remove this state from - * the object so that it doesn't mistakenly get inherited by - * a dependency. + * Now that the handle flags have been established, remove any + * handle definition from the referenced object so that the + * definitions don't mistakenly get inherited by a dependency. */ oflags = FLAGS(nlmp); - FLAGS(nlmp) &= ~FLG_RT_HANDLE; + FLAGS(nlmp) &= ~(FLG_RT_PUBHDL | FLG_RT_PRIHDL); DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); - if ((ghp = hdl_create(lml, nlmp, clmp, hflags, - (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == 0) + if ((ghp = hdl_create(lml, nlmp, clmp, hflags, rdflags, + cdflags)) == NULL) return (0); /* + * If the new link-map has been promoted, record this mode + * change for possible rescan use. + */ + if (promote) { + Aliste idx2; + Grp_desc *gdp; + + for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { + if (gdp->gd_depend == nlmp) { + gdp->gd_flags |= GPD_MODECHANGE; + break; + } + } + } + + /* * Add any dependencies that are already loaded, to the handle. */ if (hdl_initialize(ghp, nlmp, nmode, promote) == 0) @@ -2263,25 +2308,17 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, *hdl = ghp; /* - * If we were asked to create a handle, we're done. - */ - if ((oflags | flags) & FLG_RT_HANDLE) - return (1); - - /* - * If the handle was created to promote modes from the parent - * (caller) to the new object, then this relationship needs to - * be removed to ensure the handle doesn't prevent the new - * objects from being deleted if required. If the parent is - * the only dependency on the handle, then the handle can be - * completely removed. However, the handle may have already - * existed, in which case only the parent descriptor can be - * deleted from the handle, or at least the GPD_PROMOTE flag - * removed from the descriptor. + * If we were asked to create a public handle, we're done. * - * Fall through to carry out any group processing. - */ - free_hdl(ghp, clmp, GPD_PROMOTE); + * If this is a private handle request, then the handle is left + * intact with a GPH_PRIVATE identifier. This handle is a + * convenience for processing the dependencies of this object, + * but does not affect how this object might be dlclose()'d. + * For a private handle, fall through to carry out any group + * processing. + */ + if (oflags & FLG_RT_PUBHDL) + return (1); } /* @@ -2296,35 +2333,42 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, * Traverse the list of groups our caller is a member of and add this * new link-map to those groups. */ - DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); - for (APLIST_TRAVERSE(GROUPS(clmp), idx, ghp)) { - Aliste idx1; + for (APLIST_TRAVERSE(GROUPS(clmp), idx1, ghp)) { + Aliste idx2; Grp_desc *gdp; - int exist; + int ale; Rt_map *dlmp1; APlist *lmalp = NULL; + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); + /* * If the caller doesn't indicate that its dependencies should * be added to a handle, ignore it. This case identifies a * parent of a dlopen(RTLD_PARENT) request. */ - for (ALIST_TRAVERSE(ghp->gh_depends, idx1, gdp)) { + for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { if (gdp->gd_depend == clmp) break; } if ((gdp->gd_flags & GPD_ADDEPS) == 0) continue; - if ((exist = hdl_add(ghp, nlmp, - (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS))) == 0) + if ((gdp = hdl_add(ghp, nlmp, rdflags, &ale)) == NULL) return (0); /* + * If the new link-map has been promoted, record this mode + * change for possible rescan use. + */ + if (promote) + gdp->gd_flags |= GPD_MODECHANGE; + + /* * If this member already exists then its dependencies will * have already been processed. */ - if (exist == ALE_EXISTS) + if (ale == ALE_EXISTS) continue; /* @@ -2344,8 +2388,8 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, if (aplist_append(&lmalp, nlmp, AL_CNT_DEPCLCT) == NULL) return (0); - for (APLIST_TRAVERSE(lmalp, idx1, dlmp1)) { - Aliste idx2; + for (APLIST_TRAVERSE(lmalp, idx2, dlmp1)) { + Aliste idx3; Bnd_desc *bdp; /* @@ -2353,7 +2397,7 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, * dynamic dependency list so they can be further * processed. */ - for (APLIST_TRAVERSE(DEPENDS(dlmp1), idx2, bdp)) { + for (APLIST_TRAVERSE(DEPENDS(dlmp1), idx3, bdp)) { Rt_map *dlmp2 = bdp->b_depend; if ((bdp->b_flags & BND_NEEDED) == 0) @@ -2369,14 +2413,15 @@ load_finish(Lm_list *lml, const char *name, Rt_map *clmp, int nmode, if (nlmp == dlmp1) continue; - if ((exist = hdl_add(ghp, dlmp1, - (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS))) == 0) { + if ((gdp = + hdl_add(ghp, dlmp1, rdflags, &ale)) == NULL) { free(lmalp); return (0); } - if (exist == ALE_CREATE) - (void) update_mode(dlmp1, MODE(dlmp1), nmode); + if ((ale == ALE_CREATE) && + (update_mode(dlmp1, MODE(dlmp1), nmode))) + gdp->gd_flags |= GPD_MODECHANGE; } free(lmalp); } @@ -2860,7 +2905,7 @@ core_lookup_sym(Rt_map *ilmp, Slookup *slp, Rt_map **dlmp, uint_t *binfo, } static Sym * -_lazy_find_sym(Rt_map *ilmp, Slookup *slp, Rt_map **dlmp, uint_t *binfo, +rescan_lazy_find_sym(Rt_map *ilmp, Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) { Rt_map *lmp; @@ -2941,7 +2986,7 @@ _lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) lmp = 0; if (bound < SYMINFO_BT_LOWRESERVE) lmp = elf_lazy_load(clmp, slp, bound, - name, in_nfavl); + name, 0, NULL, in_nfavl); /* * If direct bindings have been disabled, and this isn't @@ -3071,15 +3116,16 @@ _lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) * initial link-map. */ if (sl.sl_flags & LKUP_NEXT) - sym = _lazy_find_sym(clmp, &sl, dlmp, binfo, in_nfavl); + sym = rescan_lazy_find_sym(clmp, &sl, dlmp, binfo, + in_nfavl); else { Aliste idx; Lm_cntl *lmc; for (ALIST_TRAVERSE(lml->lm_lists, idx, lmc)) { sl.sl_flags |= LKUP_NOFALLBACK; - if ((sym = _lazy_find_sym(lmc->lc_head, &sl, - dlmp, binfo, in_nfavl)) != 0) + if ((sym = rescan_lazy_find_sym(lmc->lc_head, + &sl, dlmp, binfo, in_nfavl)) != NULL) break; } } @@ -3101,7 +3147,7 @@ Sym * lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) { Rt_map *clmp = slp->sl_cmap; - Sym *rsym = slp->sl_rsym, *sym = 0; + Sym *rsym = slp->sl_rsym, *sym = NULL; uchar_t rtype = slp->sl_rtype; int mode; @@ -3161,9 +3207,9 @@ lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) /* * Try the symbol search again. This retry can be necessary if: * - * . a binding has been rejected because of binding to a + * - a binding has been rejected because of binding to a * singleton without going through a singleton search. - * . a group binding has resulted in binding to a symbol + * - a group binding has resulted in binding to a symbol * that indicates no-direct binding. * * Reset the lookup data, and try again. diff --git a/usr/src/cmd/sgs/rtld/common/cap.c b/usr/src/cmd/sgs/rtld/common/cap.c index 3b6ec98391..1ad4525cbc 100644 --- a/usr/src/cmd/sgs/rtld/common/cap.c +++ b/usr/src/cmd/sgs/rtld/common/cap.c @@ -262,7 +262,7 @@ hwcap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco, DBG_CALL(Dbg_file_filtee(lml, NAME(flmp), fdp->fd_nname, 0)); nlmp = load_path(lml, nlmco, flmp, mode, - (flags | FLG_RT_HANDLE), &ghp, fdp, &rej, in_nfavl); + (flags | FLG_RT_PUBHDL), &ghp, fdp, &rej, in_nfavl); if (nlmp == NULL) continue; @@ -316,7 +316,8 @@ hwcap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco, * filter and filtee if necessary. */ DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); - if (nlmp && ghp && (hdl_add(ghp, flmp, GPD_FILTER) == 0)) + if (nlmp && ghp && + (hdl_add(ghp, flmp, GPD_FILTER, NULL) == NULL)) nlmp = NULL; /* diff --git a/usr/src/cmd/sgs/rtld/common/debug.c b/usr/src/cmd/sgs/rtld/common/debug.c index 1fde0068c0..377a2da34a 100644 --- a/usr/src/cmd/sgs/rtld/common/debug.c +++ b/usr/src/cmd/sgs/rtld/common/debug.c @@ -35,6 +35,7 @@ #include <string.h> #include <thread.h> #include <debug.h> +#include <conv.h> #include "_rtld.h" #include "_elf.h" #include "msg.h" @@ -272,8 +273,6 @@ dbg_print(Lm_list *lml, const char *format, ...) } } - prf.pr_buf = prf.pr_cur = buffer; - prf.pr_len = ERRSIZE; prf.pr_fd = dbg_fd; /* @@ -281,6 +280,37 @@ dbg_print(Lm_list *lml, const char *format, ...) */ _pid = getpid(); + /* + * Each time ld.so.1 is entered, the diagnostic times are reset. It is + * useful to convey this reset as part of our diagnostics, but only if + * other diagnostics will follow. If a reset has preceded this + * diagnostic, print a division line. + */ + if (DBG_ISRESET()) { + DBG_OFFRESET(); + + prf.pr_buf = prf.pr_cur = buffer; + prf.pr_len = ERRSIZE; + + if (lml) + (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); + else + (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); + prf.pr_cur--; + + (void) bufprint(&prf, MSG_ORIG(MSG_DBG_RESET)); + (void) dowrite(&prf); + } + + /* + * Reestablish the buffer for standard printing. + */ + prf.pr_buf = prf.pr_cur = buffer; + prf.pr_len = ERRSIZE; + + /* + * Establish any diagnostic prefix strings. + */ if (lml) (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); else @@ -291,6 +321,25 @@ dbg_print(Lm_list *lml, const char *format, ...) (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); prf.pr_cur--; } + if (DBG_ISTIME()) { + struct timeval new; + + if (gettimeofday(&new, NULL) == 0) { + Conv_time_buf_t buf; + + if (DBG_ISTTIME()) { + (void) bufprint(&prf, + conv_time(&DBG_TOTALTIME, &new, &buf)); + prf.pr_cur--; + } + if (DBG_ISDTIME()) { + (void) bufprint(&prf, + conv_time(&DBG_DELTATIME, &new, &buf)); + prf.pr_cur--; + } + DBG_DELTATIME = new; + } + } if (rtld_flags & RT_FL_THREADS) { (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); prf.pr_cur--; diff --git a/usr/src/cmd/sgs/rtld/common/dlfcns.c b/usr/src/cmd/sgs/rtld/common/dlfcns.c index 02ebfb8715..373a859983 100644 --- a/usr/src/cmd/sgs/rtld/common/dlfcns.c +++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c @@ -119,15 +119,16 @@ dlerror() /* * Add a dependency as a group descriptor to a group handle. Returns 0 on - * failure, ALE_EXISTS if the dependency already exists, or ALE_CREATE if it - * is newly created. + * failure. On success, returns the group descriptor, and if alep is non-NULL + * the *alep is set to ALE_EXISTS if the dependency already exists, or to + * ALE_CREATE if the dependency is newly created. */ -int -hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t flags) +Grp_desc * +hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t dflags, int *alep) { Grp_desc *gdp; Aliste idx; - int found = ALE_CREATE; + int ale = ALE_CREATE; uint_t oflags; /* @@ -135,12 +136,12 @@ hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t flags) */ for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { if (gdp->gd_depend == lmp) { - found = ALE_EXISTS; + ale = ALE_EXISTS; break; } } - if (found == ALE_CREATE) { + if (ale == ALE_CREATE) { Grp_desc gd; /* @@ -153,49 +154,63 @@ hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t flags) * Indicate this object is a part of this handles group. */ if (aplist_append(&GROUPS(lmp), ghp, AL_CNT_GROUPS) == NULL) - return (0); + return (NULL); /* * Append the new dependency to this handle. */ if ((gdp = alist_append(&ghp->gh_depends, &gd, sizeof (Grp_desc), AL_CNT_DEPENDS)) == NULL) - return (0); + return (NULL); } oflags = gdp->gd_flags; - gdp->gd_flags |= flags; + gdp->gd_flags |= dflags; if (DBG_ENABLED) { - if (found == ALE_CREATE) + if (ale == ALE_CREATE) DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_ADD, gdp->gd_flags)); else if (gdp->gd_flags != oflags) DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_UPDATE, gdp->gd_flags)); } - return (found); + + if (alep) + *alep = ale; + return (gdp); } /* * Create a handle. + * + * rlmp - represents the reference link-map for which the handle is being + * created. + * clmp - represents the caller who is requesting the handle. + * hflags - provide group handle flags (GPH_*) that affect the use of the + * handle, such as dlopen(0), or use or use of RTLD_FIRST. + * rdflags - provide group dependency flags for the reference link-map rlmp, + * such as whether the dependency can be used for dlsym(), can be + * relocated against, or whether this objects dependencies should + * be processed. + * cdflags - provide group dependency flags for the caller. */ Grp_hdl * -hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, - uint_t ndflags, uint_t cdflags) +hdl_create(Lm_list *lml, Rt_map *rlmp, Rt_map *clmp, uint_t hflags, + uint_t rdflags, uint_t cdflags) { - Grp_hdl *ghp = NULL, *_ghp; + Grp_hdl *ghp = NULL, *aghp; APlist **alpp; Aliste idx; /* * For dlopen(0) the handle is maintained as part of the link-map list, - * otherwise it is associated with the referenced link-map. + * otherwise the handle is associated with the reference link-map. */ if (hflags & GPH_ZERO) alpp = &(lml->lm_handle); else - alpp = &(HANDLES(nlmp)); + alpp = &(HANDLES(rlmp)); /* * Objects can contain multiple handles depending on the handle flags @@ -206,9 +221,9 @@ hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, * sense for RTLD_FIRST. Determine if an appropriate handle already * exists. */ - for (APLIST_TRAVERSE(*alpp, idx, _ghp)) { - if ((_ghp->gh_flags & GPH_FIRST) == (hflags & GPH_FIRST)) { - ghp = _ghp; + for (APLIST_TRAVERSE(*alpp, idx, aghp)) { + if ((aghp->gh_flags & GPH_FIRST) == (hflags & GPH_FIRST)) { + ghp = aghp; break; } } @@ -216,12 +231,12 @@ hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, if (ghp == NULL) { uint_t ndx; - DBG_CALL(Dbg_file_hdl_title(DBG_HDL_CREATE)); - /* - * If this is the first dlopen() request for this handle - * allocate and initialize a new handle. + * If this is the first request for this handle, allocate and + * initialize a new handle. */ + DBG_CALL(Dbg_file_hdl_title(DBG_HDL_CREATE)); + if ((ghp = malloc(sizeof (Grp_hdl))) == NULL) return (NULL); @@ -262,18 +277,27 @@ hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, ghp->gh_ownlmp = lml->lm_head; ghp->gh_ownlml = lml; } else { - ghp->gh_ownlmp = nlmp; - ghp->gh_ownlml = LIST(nlmp); + ghp->gh_ownlmp = rlmp; + ghp->gh_ownlml = LIST(rlmp); - if (hdl_add(ghp, nlmp, ndflags) == 0) + if (hdl_add(ghp, rlmp, rdflags, NULL) == NULL) return (NULL); /* - * Indicate that a local group now exists. This state - * allows singleton searches to be optimized. + * If this new handle is a private handle, there's no + * need to track the caller, so we're done. + */ + if (hflags & GPH_PRIVATE) + return (ghp); + + /* + * If this new handle is public, and isn't a special + * handle representing ld.so.1, indicate that a local + * group now exists. This state allows singleton + * searches to be optimized. */ if ((hflags & GPH_LDSO) == 0) - LIST(nlmp)->lm_flags |= LML_FLG_GROUPSEXIST; + LIST(rlmp)->lm_flags |= LML_FLG_GROUPSEXIST; } } else { /* @@ -310,14 +334,37 @@ hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags, gdp->gd_depend, DBG_DEP_REINST, 0)); } } + + /* + * If we've been asked to create a private handle, there's no + * need to track the caller. + */ + if (hflags & GPH_PRIVATE) { + /* + * Negate the reference count increment. + */ + ghp->gh_refcnt--; + return (ghp); + } else { + /* + * If a private handle already exists, promote this + * handle to public by initializing both the reference + * count and the handle flags. + */ + if (ghp->gh_flags & GPH_PRIVATE) { + ghp->gh_refcnt = 1; + ghp->gh_flags &= ~GPH_PRIVATE; + ghp->gh_flags |= hflags; + } + } } /* - * Keep track of the parent (caller). As this object could be opened + * Keep track of the parent (caller). As this object can be referenced * by different parents, this processing is carried out every time a * handle is requested. */ - if (clmp && (hdl_add(ghp, clmp, cdflags) == 0)) + if (clmp && (hdl_add(ghp, clmp, cdflags, NULL) == NULL)) return (NULL); return (ghp); @@ -353,7 +400,7 @@ hdl_initialize(Grp_hdl *ghp, Rt_map *nlmp, int mode, int promote) DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { - Rt_map * lmp = gdp->gd_depend; + Rt_map *lmp = gdp->gd_depend; Aliste idx1; Bnd_desc *bdp; @@ -366,16 +413,19 @@ hdl_initialize(Grp_hdl *ghp, Rt_map *nlmp, int mode, int promote) continue; for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) { + Grp_desc *gdp; Rt_map *dlmp = bdp->b_depend; if ((bdp->b_flags & BND_NEEDED) == 0) continue; - if (hdl_add(ghp, dlmp, - (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS)) == 0) + if ((gdp = hdl_add(ghp, dlmp, + (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), + NULL)) == NULL) return (0); - (void) update_mode(dlmp, MODE(dlmp), mode); + if (update_mode(dlmp, MODE(dlmp), mode)) + gdp->gd_flags |= GPD_MODECHANGE; } } ghp->gh_flags |= GPH_INITIAL; @@ -595,37 +645,48 @@ dlmopen_core(Lm_list *lml, Lm_list *olml, const char *path, int mode, */ if (path == NULL) { Grp_hdl *ghp; - uint_t hflags = GPH_ZERO, cdflags = GPD_PARENT; + uint_t hflags, rdflags, cdflags; int promote = 0; /* * Establish any flags for the handle (Grp_hdl). * - * . This is a dummy handle (0) that provides for a dynamic - * search of all global objects within the process. - * - * . Use of the RTLD_FIRST flag indicates that only the first - * dependency on the handle (the new object) can be used - * to satisfy dlsym() requests. + * - This is a dummy, public, handle (0) that provides for a + * dynamic search of all global objects within the process. + * - Use of the RTLD_FIRST mode indicates that only the first + * dependency on the handle (the referenced object) can be + * used to satisfy dlsym() requests. */ + hflags = (GPH_PUBLIC | GPH_ZERO); if (mode & RTLD_FIRST) hflags |= GPH_FIRST; /* - * Establish the flags for this callers dependency descriptor + * Establish the flags for the referenced dependency descriptor * (Grp_desc). * - * . The explicit creation of a handle creates a descriptor - * for the new object and the parent (caller), + * - The referenced object is available for dlsym(). + * - The referenced object is available to relocate against. + * - The referenced object should have it's dependencies + * added to this handle. + */ + rdflags = (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS); + + /* + * Establish the flags for this callers dependency descriptor + * (Grp_desc). * - * . Use of the RTLD_PARENT flag indicates that the parent + * - The explicit creation of a handle creates a descriptor + * for the referenced object and the parent (caller). + * - Use of the RTLD_PARENT flag indicates that the parent * can be relocated against. */ + cdflags = GPD_PARENT; if (mode & RTLD_PARENT) cdflags |= GPD_RELOC; - if ((ghp = hdl_create(lml, 0, clmp, hflags, - (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == NULL) + if ((ghp = hdl_create(lml, 0, clmp, hflags, rdflags, + cdflags)) == NULL) return (NULL); /* @@ -682,7 +743,7 @@ dlmopen_core(Lm_list *lml, Lm_list *olml, const char *path, int mode, } olmco = nlmco; - nlmp = load_one(lml, nlmco, palp, clmp, mode, (flags | FLG_RT_HANDLE), + nlmp = load_one(lml, nlmco, palp, clmp, mode, (flags | FLG_RT_PUBHDL), &ghp, in_nfavl); /* @@ -1209,7 +1270,7 @@ dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp, if ((sip->si_flags & SYMINFO_FLG_DIRECT) && (sip->si_boundto < SYMINFO_BT_LOWRESERVE)) (void) elf_lazy_load(clmp, &sl, - sip->si_boundto, name, in_nfavl); + sip->si_boundto, name, 0, NULL, in_nfavl); /* * Clear the symbol index, so as not to confuse diff --git a/usr/src/cmd/sgs/rtld/common/elf.c b/usr/src/cmd/sgs/rtld/common/elf.c index 8ccd79ece4..b1e7204057 100644 --- a/usr/src/cmd/sgs/rtld/common/elf.c +++ b/usr/src/cmd/sgs/rtld/common/elf.c @@ -303,11 +303,11 @@ elf_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name, * to perform plt relocation on ld.so.1's link-map. The first time lazy loading * is called we get here to perform these initializations: * - * o elf_needed() is called to set up the DYNINFO() indexes for each lazy + * - elf_needed() is called to set up the DYNINFO() indexes for each lazy * dependency. Typically, for all other objects, this is called during * analyze_so(), but as ld.so.1 is set-contained we skip this processing. * - * o For intel, ld.so.1's JMPSLOT relocations need relative updates. These + * - For intel, ld.so.1's JMPSLOT relocations need relative updates. These * are by default skipped thus delaying all relative relocation processing * on every invocation of ld.so.1. */ @@ -332,10 +332,10 @@ elf_rtld_load() * This is a kludge to give ld.so.1 a performance benefit on i386. * It's based around two factors. * - * o JMPSLOT relocations (PLT's) actually need a relative relocation + * - JMPSLOT relocations (PLT's) actually need a relative relocation * applied to the GOT entry so that they can find PLT0. * - * o ld.so.1 does not exercise *any* PLT's before it has made a call + * - ld.so.1 does not exercise *any* PLT's before it has made a call * to elf_lazy_load(). This is because all dynamic dependencies * are recorded as lazy dependencies. */ @@ -353,12 +353,11 @@ elf_rtld_load() */ Rt_map * elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, - int *in_nfavl) + uint_t flags, Grp_hdl **hdl, int *in_nfavl) { Alist *palp = NULL; Rt_map *nlmp; Dyninfo *dip = &DYNINFO(clmp)[ndx], *pdip; - uint_t flags = 0; const char *name; Lm_list *lml = LIST(clmp); Aliste lmco; @@ -392,7 +391,7 @@ elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, * is created. */ if (dip->di_flags & FLG_DI_GROUP) - flags |= (FLG_RT_SETGROUP | FLG_RT_HANDLE); + flags |= (FLG_RT_SETGROUP | FLG_RT_PUBHDL); /* * Lazy dependencies are identified as DT_NEEDED entries with a @@ -425,7 +424,7 @@ elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, * Load the associated object. */ dip->di_info = nlmp = - load_one(lml, lmco, palp, clmp, MODE(clmp), flags, 0, in_nfavl); + load_one(lml, lmco, palp, clmp, MODE(clmp), flags, hdl, in_nfavl); /* * Remove any expanded pathname infrastructure. Reduce the pending lazy @@ -662,7 +661,7 @@ elf_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) if (pdyn->d_un.d_val & DF_P1_GROUPPERM) { dip->di_flags |= FLG_DI_GROUP; flags = - (FLG_RT_SETGROUP | FLG_RT_HANDLE); + (FLG_RT_SETGROUP | FLG_RT_PUBHDL); } } @@ -956,7 +955,7 @@ _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, DBG_CALL(Dbg_cap_hw_filter(lml, dir, ilmp)); if (hwcap_filtees((Alist **)&dip->di_info, idx, dir, lmco, ilmp, filtees, mode, - (FLG_RT_HANDLE | FLG_RT_HWCAP), in_nfavl) == 0) { + (FLG_RT_PUBHDL | FLG_RT_HWCAP), in_nfavl) == 0) { if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && (dip->di_flags & FLG_DI_AUXFLTR) && (rtld_flags & RT_FL_WARNFLTR)) { @@ -1014,20 +1013,49 @@ _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, #else if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) { #endif + uint_t hflags, rdflags, cdflags; + + /* + * Establish any flags for the handle (Grp_hdl). + * + * - This is a special, public, ld.so.1 + * handle. + * - Only the first object on this handle + * can supply symbols. + * - This handle provides a filtee. + * + * Essentially, this handle allows a caller to + * reference the dl*() family of interfaces from + * ld.so.1. + */ + hflags = (GPH_PUBLIC | GPH_LDSO | + GPH_FIRST | GPH_FILTEE); + + /* + * Establish the flags for the referenced + * dependency descriptor (Grp_desc). + * + * - ld.so.1 is available for dlsym(). + * - ld.so.1 is available to relocate + * against. + * - There's no need to add an dependencies + * to this handle. + */ + rdflags = (GPD_DLSYM | GPD_RELOC); + /* - * Create an association between ld.so.1 and the - * filter. As an optimization, a handle for - * ld.so.1 itself (required for the dlopen() - * family filtering mechanism) shouldn't search - * any dependencies of ld.so.1. Omitting - * GPD_ADDEPS prevents the addition of any - * ld.so.1 dependencies to this handle. + * Establish the flags for this callers + * dependency descriptor (Grp_desc). + * + * - The explicit creation of a handle + * creates a descriptor for the referenced + * object and the parent (caller). */ + cdflags = GPD_PARENT; + nlmp = lml_rtld.lm_head; if ((ghp = hdl_create(&lml_rtld, nlmp, ilmp, - (GPH_LDSO | GPH_FIRST | GPH_FILTEE), - (GPD_DLSYM | GPD_RELOC), GPD_PARENT)) == - NULL) + hflags, rdflags, cdflags)) == NULL) nlmp = NULL; /* @@ -1072,10 +1100,10 @@ _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, * Locate and load the filtee. */ if ((nlmp = load_path(lml, lmco, ilmp, mode, - FLG_RT_HANDLE, &ghp, &fd, &rej, + FLG_RT_PUBHDL, &ghp, &fd, &rej, in_nfavl)) == NULL) file_notfound(LIST(ilmp), filtee, ilmp, - FLG_RT_HANDLE, &rej); + FLG_RT_PUBHDL, &rej); filtee = pdp->pd_pname; @@ -1126,8 +1154,8 @@ _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, * necessary. */ DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); - if (nlmp && ghp && - (hdl_add(ghp, ilmp, GPD_FILTER) == 0)) + if (nlmp && ghp && (hdl_add(ghp, ilmp, + GPD_FILTER, NULL) == NULL)) nlmp = NULL; /* @@ -1258,17 +1286,17 @@ _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, * produced. ldd(1) employs printf(), and here, the selection of whether to * print a diagnostic in regards to auxiliary filters is a little more complex. * - * . The determination of whether to produce an ldd message, or a fatal + * - The determination of whether to produce an ldd message, or a fatal * error message is driven by LML_FLG_TRC_ENABLE. - * . More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN, + * - More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN, * (ldd -d/-r), LML_FLG_TRC_VERBOSE (ldd -v), LML_FLG_TRC_SEARCH (ldd -s), * and LML_FLG_TRC_UNREF/LML_FLG_TRC_UNUSED (ldd -U/-u). * - * . If the calling object is lddstub, then several classes of message are + * - If the calling object is lddstub, then several classes of message are * suppressed. The user isn't trying to diagnose lddstub, this is simply * a stub executable employed to preload a user specified library against. * - * . If RT_FL_SILENCERR is in effect then any generic ldd() messages should + * - If RT_FL_SILENCERR is in effect then any generic ldd() messages should * be suppressed. All detailed ldd messages should still be produced. */ Sym * @@ -1924,7 +1952,7 @@ elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, FLAGS1(lmp) |= FL1_RT_DISPREL; if (dyn->d_un.d_val & DF_1_GROUP) FLAGS(lmp) |= - (FLG_RT_SETGROUP | FLG_RT_HANDLE); + (FLG_RT_SETGROUP | FLG_RT_PUBHDL); if ((dyn->d_un.d_val & DF_1_NOW) && ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { MODE(lmp) |= RTLD_NOW; @@ -2475,42 +2503,49 @@ elf_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, int flags) } } -static void -elf_lazy_cleanup(APlist *alp) -{ - Rt_map *lmp; - Aliste idx; - - /* - * Cleanup any link-maps added to this dynamic list and free it. - */ - for (APLIST_TRAVERSE(alp, idx, lmp)) - FLAGS(lmp) &= ~FLG_RT_TMPLIST; - free(alp); -} - /* * This routine is called as a last fall-back to search for a symbol from a - * standard relocation. To maintain lazy loadings goal of reducing the number - * of objects mapped, any symbol search is first carried out using the objects - * that already exist in the process (either on a link-map list or handle). - * If a symbol can't be found, and lazy dependencies are still pending, this - * routine loads the dependencies in an attempt to locate the symbol. - * - * Only new objects are inspected as we will have already inspected presently - * loaded objects before calling this routine. However, a new object may not - * be new - although the di_lmp might be zero, the object may have been mapped - * as someone elses dependency. Thus there's a possibility of some symbol - * search duplication. + * standard relocation or dlsym(). To maintain lazy loadings goal of reducing + * the number of objects mapped, any symbol search is first carried out using + * the objects that already exist in the process (either on a link-map list or + * handle). If a symbol can't be found, and lazy dependencies are still + * pending, this routine loads the dependencies in an attempt to locate the + * symbol. */ Sym * elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) { Sym *sym = NULL; - APlist *alist = NULL; - Aliste idx; - Rt_map *lmp1, *lmp = slp->sl_imap; + static APlist *alist = NULL; + Aliste idx1; + Rt_map *lmp1, *lmp = slp->sl_imap, *clmp = slp->sl_cmap; const char *name = slp->sl_name; + Slookup sl1 = *slp; + Lm_list *lml; + Lm_cntl *lmc; + + /* + * It's quite possible we've been here before to process objects, + * therefore reinitialize our dynamic list. + */ + if (alist) + aplist_reset(alist); + + /* + * Discard any relocation index from further symbol searches. This + * index has already been used to trigger any necessary lazy-loads, + * and it might be because one of these lazy loads has failed that + * we're performing this fallback. By removing the relocation index + * we don't try and perform the same failed lazy loading activity again. + */ + sl1.sl_rsymndx = 0; + + /* + * Determine the callers link-map list so that we can monitor whether + * new objects have been added. + */ + lml = LIST(clmp); + lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, CNTL(clmp)); /* * Generate a local list of new objects to process. This list can grow @@ -2518,24 +2553,12 @@ elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) */ if (aplist_append(&alist, lmp, AL_CNT_LAZYFIND) == NULL) return (NULL); - FLAGS(lmp) |= FLG_RT_TMPLIST; - for (APLIST_TRAVERSE(alist, idx, lmp1)) { + for (APLIST_TRAVERSE(alist, idx1, lmp1)) { uint_t cnt = 0; - Slookup sl = *slp; Dyninfo *dip, *pdip; /* - * Discard any relocation index from further symbol searches. - * This index will have already been used to trigger any - * necessary lazy-loads, and it might be because one of these - * lazy loads have failed that we're here performing this - * fallback. By removing the relocation index we don't try - * and perform the same failed lazy loading activity again. - */ - sl.sl_rsymndx = 0; - - /* * Loop through the lazy DT_NEEDED entries examining each object * for the required symbol. If the symbol is not found, the * object is in turn added to the local alist, so that the @@ -2544,7 +2567,11 @@ elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) lmp = lmp1; for (dip = DYNINFO(lmp), pdip = NULL; cnt < DYNINFOCNT(lmp); cnt++, pdip = dip++) { - Rt_map *nlmp; + Grp_hdl *ghp; + Grp_desc *gdp; + Rt_map *nlmp, *llmp; + Slookup sl2; + Aliste idx2; if (((dip->di_flags & FLG_DI_LAZY) == 0) || dip->di_info) @@ -2566,57 +2593,102 @@ elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) } /* + * Determine the last link-map presently on the callers + * link-map control list. + */ + llmp = lmc->lc_tail; + + /* * Try loading this lazy dependency. If the object * can't be loaded, consider this non-fatal and continue * the search. Lazy loaded dependencies need not exist * and their loading should only turn out to be fatal * if they are required to satisfy a relocation. * - * If the file is already loaded and relocated we must - * still inspect it for symbols, even though it might - * have already been searched. This lazy load operation - * might have promoted the permissions of the object, - * and thus made the object applicable for this symbol - * search, whereas before the object might have been - * skipped. + * A successful lazy load can mean one of two things: + * + * - new objects have been loaded, in which case the + * objects will have been analyzed, relocated, and + * finally moved to the callers control list. + * - the objects are already loaded, and this lazy + * load has simply associated the referenced object + * with it's lazy dependencies. + * + * If new objects are loaded, look in these objects + * first. Note, a new object can be the object being + * referenced by this lazy load, however we can also + * descend into multiple lazy loads as we relocate this + * reference. + * + * If the symbol hasn't been found, use the referenced + * objects handle, as it might have dependencies on + * objects that are already loaded. We only need to + * look in any existing objects if the mode of those + * objects has changed. Existing objects would have + * already been searched, however, a lazy load might + * still cause the promotion of modes, and in this case + * the handle associated with the object is used to + * carry out the symbol search. */ - if ((nlmp = elf_lazy_load(lmp, &sl, cnt, - name, in_nfavl)) == NULL) + if ((nlmp = elf_lazy_load(lmp, &sl1, cnt, name, + FLG_RT_PRIHDL, &ghp, in_nfavl)) == NULL) continue; + if (NEXT_RT_MAP(llmp)) { + /* + * Look in any new objects. + */ + sl1.sl_imap = NEXT_RT_MAP(llmp); + sl1.sl_flags &= ~LKUP_STDRELOC; + + sym = lookup_sym(&sl1, _lmp, binfo, in_nfavl); + } + /* - * If this object isn't yet a part of the dynamic list - * then inspect it for the symbol. If the symbol isn't - * found add the object to the dynamic list so that we - * can inspect its dependencies. + * Use the objects handle to determine any promoted + * objects. Clear any modes regardless. Note, there's + * a possibility of overlap with the above search, + * should a lazy load bring in new objects and + * reference existing objects. */ - if (FLAGS(nlmp) & FLG_RT_TMPLIST) - continue; + sl2 = sl1; + for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { + if ((gdp->gd_flags & GPD_MODECHANGE) == 0) + continue; - sl.sl_imap = nlmp; - if (sym = lookup_sym(&sl, _lmp, binfo, in_nfavl)) - break; + if ((sym == NULL) && + (gdp->gd_depend != NEXT_RT_MAP(llmp)) && + (gdp->gd_flags & GPD_DLSYM)) { + + sl2.sl_imap = gdp->gd_depend; + sl2.sl_flags |= LKUP_FIRST; + + sym = lookup_sym(&sl2, _lmp, binfo, + in_nfavl); + } + gdp->gd_flags &= ~GPD_MODECHANGE; + } + + /* + * If the symbol has been found, cleanup and return. + */ + if (sym) + return (sym); /* * Some dlsym() operations are already traversing a * link-map (dlopen(0)), and thus there's no need to - * build our own dynamic dependency list. + * save them on the dynamic dependency list. */ - if ((sl.sl_flags & LKUP_NODESCENT) == 0) { - if (aplist_append(&alist, nlmp, - AL_CNT_LAZYFIND) == NULL) { - elf_lazy_cleanup(alist); - return (NULL); - } - FLAGS(nlmp) |= FLG_RT_TMPLIST; - } + if (slp->sl_flags & LKUP_NODESCENT) + continue; + + if (aplist_test(&alist, nlmp, AL_CNT_LAZYFIND) == NULL) + return (NULL); } - if (sym) - break; } - elf_lazy_cleanup(alist); - return (sym); + return (NULL); } /* diff --git a/usr/src/cmd/sgs/rtld/common/remove.c b/usr/src/cmd/sgs/rtld/common/remove.c index 7e978f1eb5..080ec53af8 100644 --- a/usr/src/cmd/sgs/rtld/common/remove.c +++ b/usr/src/cmd/sgs/rtld/common/remove.c @@ -27,9 +27,9 @@ /* * Remove objects. Objects need removal from a process as part of: * - * o a dlclose() request + * - a dlclose() request * - * o tearing down a dlopen(), lazy-load, or filter hierarchy that failed to + * - tearing down a dlopen(), lazy-load, or filter hierarchy that failed to * completely load * * Any other failure condition will result in process exit (in which case all @@ -542,6 +542,13 @@ is_deletable(APlist **lmalp, APlist **ghalp, Rt_map *lmp) * handles we can ferret out these outsiders. */ for (APLIST_TRAVERSE(HANDLES(lmp), idx, ghp)) { + /* + * If this is a private handle, then the handle isn't referenced + * from outside of the group of objects being deleted, and can + * be ignored when evaluating objects for deletion. + */ + if (ghp->gh_flags & GPH_PRIVATE) + continue; if (aplist_test(ghalp, ghp, 0) != ALE_EXISTS) return (0); } @@ -551,8 +558,7 @@ is_deletable(APlist **lmalp, APlist **ghalp, Rt_map *lmp) * objects selected for deletion, it can't be deleted. */ for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) { - if (aplist_test(lmalp, bdp->b_caller, 0) != - ALE_EXISTS) + if (aplist_test(lmalp, bdp->b_caller, 0) != ALE_EXISTS) return (0); } @@ -612,12 +618,12 @@ gdp_collect(APlist **ghalpp, APlist **lmalpp, Grp_hdl *ghp1) * * An object is a candidate for deletion if: * - * . the object hasn't yet been relocated, in which case + * - the object hasn't yet been relocated, in which case * we're here to clean up a failed load, or - * . the object doesn't reside on the base link-map control + * - the object doesn't reside on the base link-map control * list, in which case a group of objects, typically * lazily loaded, or filtees, need cleaning up, or - * . the object isn't tagged as non-deletable. + * - the object isn't tagged as non-deletable. */ if ((((FLAGS(lmp) & FLG_RT_RELOCED) == 0) || (CNTL(lmp) != ALIST_OFF_DATA) || @@ -756,20 +762,14 @@ remove_collect(APlist *ghalp, APlist *lmalp) } /* - * Remove a handle, leaving the associated objects intact. Besides the classic - * dlopen() usage, handles are used as a means of associating a group of objects - * and promoting modes. Once object promotion is completed, the handle should - * be discarded while leaving the associated objects intact. Leaving the handle - * would prevent the object from being deleted (as it looks like it's in use - * by another user). + * Remove a handle, leaving the associated objects intact. */ void -free_hdl(Grp_hdl *ghp, Rt_map *clmp, uint_t cdflags) +free_hdl(Grp_hdl *ghp) { - Grp_desc *gdp; - Aliste idx; - if (--(ghp->gh_refcnt) == 0) { + Grp_desc *gdp; + Aliste idx; uintptr_t ndx; for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { @@ -786,29 +786,6 @@ free_hdl(Grp_hdl *ghp, Rt_map *clmp, uint_t cdflags) (void) aplist_delete_value(hdl_alp[ndx], ghp); (void) free(ghp); - - } else if (clmp) { - /* - * It's possible that an RTLD_NOW promotion (via GPD_PROMOTE) - * has associated a caller with a handle that is already in use. - * In this case, find the caller and either remove the caller - * from the handle, or if the caller is used for any other - * reason, clear the promotion flag. - */ - for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { - Rt_map *lmp = gdp->gd_depend; - - if (lmp != clmp) - continue; - - if (gdp->gd_flags == cdflags) { - alist_delete(ghp->gh_depends, &idx); - (void) aplist_delete_value(GROUPS(lmp), ghp); - } else { - gdp->gd_flags &= ~cdflags; - } - return; - } } } @@ -865,12 +842,18 @@ remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name) if (HANDLES(lmp)) { ghp = (Grp_hdl *)HANDLES(lmp)->apl_data[0]; + /* + * If this is a private handle, remove this state, so as to + * prevent any attempt to remove the handle more than once. + */ + ghp->gh_flags &= ~GPH_PRIVATE; + } else if (lmc->lc_flags & LMC_FLG_RELOCATING) { /* * Establish a handle, and should anything fail, fall through * to remove the link-map control list. */ - if (((ghp = hdl_create(lml, lmc->lc_head, 0, 0, + if (((ghp = hdl_create(lml, lmc->lc_head, NULL, GPH_PUBLIC, GPD_ADDEPS, 0)) == NULL) || (hdl_initialize(ghp, lmc->lc_head, 0, 0) == 0)) lmc->lc_flags &= ~LMC_FLG_RELOCATING; @@ -887,7 +870,7 @@ remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name) if (ghp) { ghp->gh_refcnt = 1; - free_hdl(ghp, 0, 0); + free_hdl(ghp); } return; } @@ -981,18 +964,18 @@ remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name) * cised to make sure any filtees found aren't being used by filters outside of * the groups we've collect. The series of events is basically: * - * o Determine the groups (handles) that might be deletable. + * - Determine the groups (handles) that might be deletable. * - * o Determine the objects of these handles that can be deleted. + * - Determine the objects of these handles that can be deleted. * - * o Fire the fini's of those objects selected for deletion. + * - Fire the fini's of those objects selected for deletion. * - * o Remove all inter-dependency linked lists while the objects link-maps + * - Remove all inter-dependency linked lists while the objects link-maps * are still available. * - * o Remove all deletable objects link-maps and unmap the objects themselves. + * - Remove all deletable objects link-maps and unmap the objects themselves. * - * o Remove the handle descriptors for each deleted object, and hopefully + * - Remove the handle descriptors for each deleted object, and hopefully * the whole handle. * * An handle that can't be deleted is added to an orphans list. This list is @@ -1257,6 +1240,8 @@ remove_hdl(Grp_hdl *ghp, Rt_map *clmp, int *removed) DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE)); for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { + Grp_hdl *ghp3; + Aliste idx3; int flag; lmp = gdp->gd_depend; @@ -1287,6 +1272,15 @@ remove_hdl(Grp_hdl *ghp, Rt_map *clmp, int *removed) flag = DBG_DEP_REMAIN; DBG_CALL(Dbg_file_hdl_action(ghp, lmp, flag, 0)); + + /* + * If this object contains any private handles, remove + * them now. + */ + for (APLIST_TRAVERSE(HANDLES(lmp), idx3, ghp3)) { + if (ghp3->gh_flags & GPH_PRIVATE) + free_hdl(ghp3); + } } } diff --git a/usr/src/cmd/sgs/rtld/common/rtld.msg b/usr/src/cmd/sgs/rtld/common/rtld.msg index eba3d4d274..919009d3a3 100644 --- a/usr/src/cmd/sgs/rtld/common/rtld.msg +++ b/usr/src/cmd/sgs/rtld/common/rtld.msg @@ -378,6 +378,7 @@ @ MSG_EMG_ENOMEM "internal: Not enough space" @ MSG_DBG_PID "%5.5d: " +@ MSG_DBG_RESET "---------\n" @ MSG_DBG_UNDEF "debug: " @ MSG_DBG_LMID "%s: " @ MSG_DBG_THREAD "%d: " diff --git a/usr/src/cmd/sgs/rtld/common/setup.c b/usr/src/cmd/sgs/rtld/common/setup.c index 2ac3070ca5..cecdf4f2c0 100644 --- a/usr/src/cmd/sgs/rtld/common/setup.c +++ b/usr/src/cmd/sgs/rtld/common/setup.c @@ -197,14 +197,23 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, /* * Now that ld.so has relocated itself, initialize our own 'environ' so - * as to establish an address suitable for libc's hardware mul/div - * magic (libc/sparc/crt/hwmuldiv.o). + * as to establish an address suitable for any libc requirements. */ _environ = (char **)((ulong_t)auxv - sizeof (char *)); _init(); _environ = envp; /* + * Establish a base time. Total time diagnostics start from entering + * ld.so.1 here, however the base time is reset each time the ld.so.1 + * is re-entered. Note also, there will be a large time associated + * with the first diagnostic from ld.so.1, as bootstrapping ld.so.1 + * and establishing the liblddbg infrastructure takes some time. + */ + (void) gettimeofday(&DBG_TOTALTIME, NULL); + DBG_DELTATIME = DBG_TOTALTIME; + + /* * Determine how ld.so.1 has been executed. */ if ((fd == -1) && (phdr == NULL)) { @@ -855,7 +864,9 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, * that expects the old getpid() initialization handshake. */ if ((rpl_debug || prm_debug) && ((rtld_flags & RT_FL_DEBUGGER) == 0)) { - Dbg_desc _dbg_desc = {0, 0, NULL}; + Dbg_desc _dbg_desc = {0}; + struct timeval total = DBG_TOTALTIME; + struct timeval delta = DBG_DELTATIME; if (rpl_debug) { if (dbg_setup(rpl_debug, &_dbg_desc) == 0) @@ -867,6 +878,8 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, (void) dbg_setup(prm_debug, &_dbg_desc); *dbg_desc = _dbg_desc; + DBG_TOTALTIME = total; + DBG_DELTATIME = delta; } /* diff --git a/usr/src/cmd/sgs/rtld/common/util.c b/usr/src/cmd/sgs/rtld/common/util.c index f460541cc9..323d57a15e 100644 --- a/usr/src/cmd/sgs/rtld/common/util.c +++ b/usr/src/cmd/sgs/rtld/common/util.c @@ -34,6 +34,7 @@ * (with different names) to avoid name space collisions. */ #include <stdio.h> +#include <sys/time.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/lwp.h> @@ -3040,8 +3041,20 @@ enter(int flags) if (rt_bind_guard(THR_FLG_RTLD | thr_flg_nolock | flags)) { if (!thr_flg_nolock) (void) rt_mutex_lock(&rtldlock); - if (rtld_flags & RT_FL_OPERATION) + if (rtld_flags & RT_FL_OPERATION) { ld_entry_cnt++; + + /* + * Reset the diagnostic time information for each new + * "operation". Thus timing diagnostics are relative + * to entering ld.so.1. + */ + if (DBG_ISTIME() && + (gettimeofday(&DBG_TOTALTIME, NULL) == 0)) { + DBG_DELTATIME = DBG_TOTALTIME; + DBG_ONRESET(); + } + } return (1); } return (0); diff --git a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c index b3108bdd63..e31f306261 100644 --- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c +++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c @@ -71,11 +71,11 @@ static const mdb_bitmask_t rtflags_bits[] = { { MSG_ORIG(MSG_FLG_OBJINTPO), FLG_RT_OBJINTPO, FLG_RT_OBJINTPO}, { MSG_ORIG(MSG_FLG_SYMINTPO), FLG_RT_SYMINTPO, FLG_RT_SYMINTPO}, { MSG_ORIG(MSG_FLG_MOVE), FLG_RT_MOVE, FLG_RT_MOVE}, - { MSG_ORIG(MSG_FLG_TMPLIST), FLG_RT_TMPLIST, FLG_RT_TMPLIST}, + { MSG_ORIG(MSG_FLG_RELOCING), FLG_RT_RELOCING, FLG_RT_RELOCING}, { MSG_ORIG(MSG_FLG_REGSYMS), FLG_RT_REGSYMS, FLG_RT_REGSYMS}, { MSG_ORIG(MSG_FLG_INITCLCT), FLG_RT_INITCLCT, FLG_RT_INITCLCT}, - { MSG_ORIG(MSG_FLG_HANDLE), FLG_RT_HANDLE, FLG_RT_HANDLE}, - { MSG_ORIG(MSG_FLG_RELOCING), FLG_RT_RELOCING, FLG_RT_RELOCING}, + { MSG_ORIG(MSG_FLG_PUBHDL), FLG_RT_PUBHDL, FLG_RT_PUBHDL}, + { MSG_ORIG(MSG_FLG_PRIHDL), FLG_RT_PRIHDL, FLG_RT_PRIHDL}, { NULL, 0, 0} }; @@ -145,6 +145,8 @@ static const mdb_bitmask_t bndflags_bits[] = { }; static const mdb_bitmask_t grhflags_bits[] = { + { MSG_ORIG(MSG_GPH_PUBLIC), GPH_PUBLIC, GPH_PUBLIC }, + { MSG_ORIG(MSG_GPH_PRIVATE), GPH_PRIVATE, GPH_PRIVATE }, { MSG_ORIG(MSG_GPH_ZERO), GPH_ZERO, GPH_ZERO }, { MSG_ORIG(MSG_GPH_LDSO), GPH_LDSO, GPH_LDSO }, { MSG_ORIG(MSG_GPH_FIRST), GPH_FIRST, GPH_FIRST }, @@ -160,8 +162,8 @@ static const mdb_bitmask_t grdflags_bits[] = { { MSG_ORIG(MSG_GPD_ADDEPS), GPD_ADDEPS, GPD_ADDEPS }, { MSG_ORIG(MSG_GPD_PARENT), GPD_PARENT, GPD_PARENT }, { MSG_ORIG(MSG_GPD_FILTER), GPD_FILTER, GPD_FILTER }, - { MSG_ORIG(MSG_GPD_PROMOTE), GPD_PROMOTE, GPD_PROMOTE }, { MSG_ORIG(MSG_GPD_REMOVE), GPD_REMOVE, GPD_REMOVE }, + { MSG_ORIG(MSG_GPD_MODECHANGE), GPD_MODECHANGE, GPD_MODECHANGE }, { NULL, 0, 0} }; diff --git a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg index 597316816c..d72f5c1878 100644 --- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg +++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg @@ -86,11 +86,11 @@ @ MSG_FLG_OBJINTPO "OBJECT-INTERPOSE" @ MSG_FLG_SYMINTPO "SYMBOL-INTERPOSE" @ MSG_FLG_MOVE "MOVE" -@ MSG_FLG_TMPLIST "TEMPORARY-LIST" +@ MSG_FLG_RELOCING "RELOCATING" @ MSG_FLG_REGSYMS "REGISTER-SYMS" @ MSG_FLG_INITCLCT "INIT-COLLECTED" -@ MSG_FLG_HANDLE "HANDLE" -@ MSG_FLG_RELOCING "RELOCATING" +@ MSG_FLG_PUBHDL "PUBLIC-HANDLE" +@ MSG_FLG_PRIHDL "PRIVATE-HANDLE" @ MSG_FL1_COPYTOOK "COPYTOOK" @ MSG_FL1_CONFSET "CONFSET" @@ -126,6 +126,8 @@ @ MSG_BFL_REFER "REFERENCED" @ MSG_BFL_FILTER "FILTER" +@ MSG_GPH_PUBLIC "PUBLIC-HANDLE" +@ MSG_GPH_PRIVATE "PRIVATE-HANDLE" @ MSG_GPH_ZERO "ZERO" @ MSG_GPH_LDSO "LD.SO.1" @ MSG_GPH_FIRST "FIRST-ONLY" @@ -139,7 +141,7 @@ @ MSG_GPD_PARENT "PARENT" @ MSG_GPD_FILTER "FILTER" @ MSG_GPD_REMOVE "REMOVAL-CANDIDATE" -@ MSG_GPD_PROMOTE "RTLD_NOW-PROMOTER" +@ MSG_GPD_MODECHANGE "MODES-HAVE-CHANGED" @ MSG_LFL_BASELM "BASELM" @ MSG_LFL_RTLDLM "RTLDLM" |