summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2008-09-24 11:26:37 -0600
committerAli Bahrami <Ali.Bahrami@Sun.COM>2008-09-24 11:26:37 -0600
commit090a8d9e70b0696e7d9bc114c6e021757c9f04fe (patch)
tree65417695add89e61d46abf32dca758a050680bfe /usr/src/cmd
parent5548c527e7ec2109f4f9ee52056afd33ada35516 (diff)
downloadillumos-joyent-090a8d9e70b0696e7d9bc114c6e021757c9f04fe.tar.gz
6749055 ld should generate GNU style VERSYM indexes for VERNEED records
PSARC/2008/603 ELF objects to adopt GNU-style Versym indexes
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.c194
-rw-r--r--usr/src/cmd/sgs/include/conv.h19
-rw-r--r--usr/src/cmd/sgs/include/libld.h6
-rw-r--r--usr/src/cmd/sgs/lari/lari.pl21
-rw-r--r--usr/src/cmd/sgs/libconv/common/llib-lconv4
-rw-r--r--usr/src/cmd/sgs/libconv/common/version.c48
-rw-r--r--usr/src/cmd/sgs/libconv/common/version.msg9
-rw-r--r--usr/src/cmd/sgs/libld/common/sections.c15
-rw-r--r--usr/src/cmd/sgs/libld/common/update.c158
-rw-r--r--usr/src/cmd/sgs/libld/common/version.c64
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/version.c14
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README2
-rw-r--r--usr/src/cmd/sgs/pvs/Makefile.com11
-rw-r--r--usr/src/cmd/sgs/pvs/Makefile.targ16
-rw-r--r--usr/src/cmd/sgs/pvs/common/lintsup.c11
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.c896
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.msg39
-rw-r--r--usr/src/cmd/sgs/rtld/common/elf.c15
18 files changed, 1091 insertions, 451 deletions
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c
index ea51519c27..69d2d9b727 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c
@@ -47,27 +47,63 @@
* in the object being analyzed. It is filled in by versions(), and used
* by init_symtbl_state() when displaying symbol information.
*
+ * There are three forms of symbol versioning known to us:
+ *
+ * 1) The original form, introduced with Solaris 2.5, in which
+ * the Versym contains indexes to Verdef records, and the
+ * Versym values for UNDEF symbols resolved by other objects
+ * are all set to 0.
+ * 2) The GNU form, which is backward compatible with the original
+ * Solaris form, but which adds several extensions:
+ * - The Versym also contains indexes to Verneed records, recording
+ * which object/version contributed the external symbol at
+ * link time. These indexes start with the next value following
+ * the final Verdef index. The index is written to the previously
+ * reserved vna_other field of the ELF Vernaux structure.
+ * - The top bit of the Versym value is no longer part of the index,
+ * but is used as a "hidden bit" to prevent binding to the symbol.
+ * - Multiple implementations of a given symbol, contained in varying
+ * versions are allowed, using special assembler pseudo ops,
+ * and encoded in the symbol name using '@' characters.
+ * 3) Modified Solaris form, in which we adopt the first GNU extension
+ * (Versym indexes to Verneed records), but not the others.
+ *
+ * elfdump can handle any of these cases. The presence of a DT_VERSYM
+ * dynamic element indicates a full GNU object. An object that lacks
+ * a DT_VERSYM entry, but which has non-zero vna_other fields in the Vernaux
+ * structures is a modified Solaris object. An object that has neither of
+ * these uses the original form.
+ *
* max_verndx contains the largest version index that can appear
* in a Versym entry. This can never be less than 1: In the case where
* there is no verdef/verneed sections, the [0] index is reserved
- * for local symbols, and the [1] index for globals. If Solaris versioning
- * rules are in effect and there is a verdef section, then the number
- * of defined versions provides this number. If GNU versioning is in effect,
- * then:
- * - If there is no verneed section, it is the same as for
- * Solaris versioning.
- * - If there is a verneed section, the vna_other field of the
+ * for local symbols, and the [1] index for globals. If the original
+ * Solaris versioning rules are in effect and there is a verdef section,
+ * then max_verndex is the number of defined versions. If one of the
+ * other versioning forms is in effect, then:
+ * 1) If there is no verneed section, it is the same as for
+ * original Solaris versioning.
+ * 2) If there is a verneed section, the vna_other field of the
* Vernaux structs contain versions, and max_verndx is the
* largest such index.
*
- * The value of the gnu field is based on the presence of
+ * If gnu_full is True, the object uses the full GNU form of versioning.
+ * The value of the gnu_full field is based on the presence of
* a DT_VERSYM entry in the dynamic section: GNU ld produces these, and
* Solaris ld does not.
+ *
+ * The gnu_needed field is True if the Versym contains indexes to
+ * Verneed records, as indicated by non-zero vna_other fields in the Verneed
+ * section. If gnu_full is True, then gnu_needed will always be true.
+ * However, gnu_needed can be true without gnu_full. This is the modified
+ * Solaris form.
*/
typedef struct {
Cache *cache; /* Pointer to cache entry for VERSYM */
Versym *data; /* Pointer to versym array */
- int gnu; /* True if object uses GNU versioning rules */
+ int gnu_full; /* True if object uses GNU versioning rules */
+ int gnu_needed; /* True if object uses VERSYM indexes for */
+ /* VERNEED (subset of gnu_full) */
int max_verndx; /* largest versym index value */
} VERSYM_STATE;
@@ -982,10 +1018,11 @@ version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache,
for (cnt = 1; cnt <= vdf_num; cnt++,
vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
- const char *name, *dep;
- Half vcnt = vdf->vd_cnt - 1;
- Half ndx = vdf->vd_ndx;
- Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux);
+ Conv_ver_flags_buf_t ver_flags_buf;
+ const char *name, *dep;
+ Half vcnt = vdf->vd_cnt - 1;
+ Half ndx = vdf->vd_ndx;
+ Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux);
/*
* Obtain the name and first dependency (if any).
@@ -1000,7 +1037,7 @@ version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache,
(void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
EC_XWORD(ndx));
Elf_ver_line_1(0, index, name, dep,
- conv_ver_flags(vdf->vd_flags));
+ conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf));
/*
* Print any additional dependencies.
@@ -1033,6 +1070,26 @@ version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache,
* The versions have been printed. If GNU style versioning
* is in effect, versym->max_verndx has been updated to
* contain the largest version index seen.
+ *
+ * note:
+ * The versym section of an object that follows the original
+ * Solaris versioning rules only contains indexes into the verdef
+ * section. Symbols defined in other objects (UNDEF) are given
+ * a version of 0, indicating that they are not defined by
+ * this file, and the Verneed entries do not have associated version
+ * indexes. For these reasons, we do not display a version index
+ * for original-style Verneed sections.
+ *
+ * The GNU versioning extensions alter this: Symbols defined in other
+ * objects receive a version index in the range above those defined
+ * by the Verdef section, and the vna_other field of the Vernaux
+ * structs inside the Verneed section contain the version index for
+ * that item. We therefore display the index when showing the
+ * contents of a GNU style Verneed section. You should not
+ * necessarily expect these indexes to appear in sorted
+ * order --- it seems that the GNU ld assigns the versions as
+ * symbols are encountered during linking, and then the results
+ * are assembled into the Verneed section afterwards.
*/
static void
version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
@@ -1042,38 +1099,13 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
char index[MAXNDXSIZE];
const char *index_str;
- Elf_ver_need_title(0, versym->gnu);
-
- /*
- * The versym section in an object that follows Solaris versioning
- * rules contains indexes into the verdef section. Symbols defined
- * in other objects (UNDEF) are given a version of 0, indicating that
- * they are not defined by this file, and the Verneed entries do not
- * have associated version indexes. For these reasons, we do not
- * display a version index for Solaris Verneed sections.
- *
- * The GNU versioning rules are different: Symbols defined in other
- * objects receive a version index in the range above those defined
- * by the Verdef section, and the vna_other field of the Vernaux
- * structs inside the Verneed section contain the version index for
- * that item. We therefore display the index when showing the
- * contents of a GNU Verneed section. You should not expect these
- * indexes to appear in sorted order --- it seems that the GNU ld
- * assigns the versions as symbols are encountered during linking,
- * and then the results are assembled into the Verneed section
- * afterwards.
- */
- if (versym->gnu) {
- index_str = index;
- } else {
- /* For Solaris versioning, display a NULL string */
- index_str = MSG_ORIG(MSG_STR_EMPTY);
- }
+ Elf_ver_need_title(0, versym->gnu_needed);
for (cnt = 1; cnt <= vnd_num; cnt++,
vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
- const char *name, *dep;
- Half vcnt = vnd->vn_cnt;
+ Conv_ver_flags_buf_t ver_flags_buf;
+ const char *name, *dep;
+ Half vcnt = vnd->vn_cnt;
Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux);
/*
@@ -1088,7 +1120,10 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
else
dep = MSG_INTL(MSG_STR_NULL);
- if (versym->gnu) {
+ if (vnap->vna_other == 0) { /* Traditional form */
+ index_str = MSG_ORIG(MSG_STR_EMPTY);
+ } else { /* GNU form */
+ index_str = index;
/* Format the version index value */
(void) snprintf(index, MAXNDXSIZE,
MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other));
@@ -1096,7 +1131,7 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
versym->max_verndx = vnap->vna_other;
}
Elf_ver_line_1(0, index_str, name, dep,
- conv_ver_flags(vnap->vna_flags));
+ conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf));
/*
* Print any additional version dependencies.
@@ -1108,14 +1143,15 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
vnap->vna_next)) {
dep = string(vcache, cnt, scache, file,
vnap->vna_name);
- if (versym->gnu) {
+ if (vnap->vna_other > 0) {
/* Format the next index value */
(void) snprintf(index, MAXNDXSIZE,
MSG_ORIG(MSG_FMT_INDEX),
EC_XWORD(vnap->vna_other));
- Elf_ver_line_1(0, index_str,
+ Elf_ver_line_1(0, index,
MSG_ORIG(MSG_STR_EMPTY), dep,
- conv_ver_flags(vnap->vna_flags));
+ conv_ver_flags(vnap->vna_flags,
+ 0, &ver_flags_buf));
if (vnap->vna_other >
versym->max_verndx)
versym->max_verndx =
@@ -1123,7 +1159,8 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
} else {
Elf_ver_line_3(0,
MSG_ORIG(MSG_STR_EMPTY), dep,
- conv_ver_flags(vnap->vna_flags));
+ conv_ver_flags(vnap->vna_flags,
+ 0, &ver_flags_buf));
}
}
}
@@ -1131,9 +1168,12 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
}
/*
- * Compute the max_verndx value for a GNU style object with
- * a Verneed section. This is only needed if version_need() is not
- * called.
+ * Examine the Verneed section for information related to GNU
+ * style Versym indexing:
+ * - A non-zero vna_other field indicates that Versym indexes can
+ * reference Verneed records.
+ * - If the object uses GNU style Versym indexing, the
+ * maximum index value is needed to detect bad Versym entries.
*
* entry:
* vnd - Address of verneed data
@@ -1141,11 +1181,13 @@ version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
* versym - Information about versym section
*
* exit:
+ * If a non-zero vna_other field is seen, versym->gnu_needed is set.
+ *
* versym->max_verndx has been updated to contain the largest
* version index seen.
*/
static void
-update_gnu_max_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym)
+update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym)
{
Word cnt;
@@ -1154,8 +1196,16 @@ update_gnu_max_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym)
Half vcnt = vnd->vn_cnt;
Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux);
- if (vnap->vna_other > versym->max_verndx)
- versym->max_verndx = vnap->vna_other;
+ /*
+ * A non-zero value of vna_other indicates that this
+ * object references VERNEED items from the VERSYM
+ * array.
+ */
+ if (vnap->vna_other != 0) {
+ versym->gnu_needed = 1;
+ if (vnap->vna_other > versym->max_verndx)
+ versym->max_verndx = vnap->vna_other;
+ }
/*
* Check any additional version dependencies.
@@ -1165,6 +1215,10 @@ update_gnu_max_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym)
for (vcnt--; vcnt; vcnt--,
vnap = (Vernaux *)((uintptr_t)vnap +
vnap->vna_next)) {
+ if (vnap->vna_other == 0)
+ continue;
+
+ versym->gnu_needed = 1;
if (vnap->vna_other > versym->max_verndx)
versym->max_verndx = vnap->vna_other;
}
@@ -1220,7 +1274,8 @@ versions(Cache *cache, Word shnum, const char *file, uint_t flags,
dyn = (Dyn *)_cache->c_data->d_buf;
for (; numdyn-- > 0; dyn++)
if (dyn->d_tag == DT_VERSYM) {
- versym->gnu = 1;
+ versym->gnu_full =
+ versym->gnu_needed = 1;
break;
}
break;
@@ -1281,23 +1336,20 @@ versions(Cache *cache, Word shnum, const char *file, uint_t flags,
}
}
- if ((flags & FLG_SHOW_VERSIONS) == 0) {
- /*
- * If GNU versioning applies to this object, and there
- * is a Verneed section, then examine it to determine
- * the maximum Versym version index for this file.
- */
- if ((versym->gnu) && (verneed_cache != NULL))
- update_gnu_max_verndx(
- (Verneed *)verneed_cache->c_data->d_buf,
- verneed_cache->c_shdr->sh_info, versym);
- return;
- }
+ /*
+ * If there is a Verneed section, examine it for information
+ * related to GNU style versioning.
+ */
+ if (verneed_cache != NULL)
+ update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf,
+ verneed_cache->c_shdr->sh_info, versym);
/*
* Now that all the information is available, display the
- * Verdef and Verneed section contents.
+ * Verdef and Verneed section contents, if requested.
*/
+ if ((flags & FLG_SHOW_VERSIONS) == 0)
+ return;
if (verdef_cache != NULL) {
dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF),
@@ -1313,7 +1365,7 @@ versions(Cache *cache, Word shnum, const char *file, uint_t flags,
/*
* If GNU versioning applies to this object, version_need()
* will update versym->max_verndx, and it is not
- * necessary to call update_gnu_max_verndx().
+ * necessary to call update_gnu_verndx().
*/
version_need((Verneed *)verneed_cache->c_data->d_buf,
verneed_cache->c_shdr->sh_info, verneed_cache,
@@ -1545,7 +1597,7 @@ output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx,
Versym test_verndx;
verndx = test_verndx = state->versym->data[symndx];
- gnuver = state->versym->gnu;
+ gnuver = state->versym->gnu_full;
/*
* Check to see if this is a defined symbol with a
diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h
index 1a0e10fe8d..d9fccb6a62 100644
--- a/usr/src/cmd/sgs/include/conv.h
+++ b/usr/src/cmd/sgs/include/conv.h
@@ -30,8 +30,6 @@
#ifndef _CONV_H
#define _CONV_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Global include file for conversion library.
*/
@@ -571,6 +569,18 @@ typedef union {
} Conv64_cnote_auxv_af_buf_t;
+/* conv_ver_flags() */
+#define CONV_VER_FLAGS_BUFSIZE 31
+typedef union {
+ Conv32_inv_buf_t inv_buf;
+ char buf[CONV_VER_FLAGS_BUFSIZE];
+} Conv32_ver_flags_buf_t;
+typedef union {
+ Conv64_inv_buf_t inv_buf;
+ char buf[CONV_VER_FLAGS_BUFSIZE];
+} Conv64_ver_flags_buf_t;
+
+
/*
* Generic names for class specific buffer types above
@@ -621,6 +631,7 @@ typedef union {
#define Conv_cnote_ss_flags_buf_t Conv64_cnote_ss_flags_buf_t
#define Conv_cnote_cc_content_buf_t Conv64_cnote_cc_content_buf_t
#define Conv_cnote_auxv_af_buf_t Conv64_cnote_auxv_af_buf_t
+#define Conv_ver_flags_buf_t Conv64_ver_flags_buf_t
#else
#define CONV_INV_BUFSIZE CONV32_INV_BUFSIZE
#define CONV_EHDR_FLAGS_BUFSIZE CONV32_EHDR_FLAGS_BUFSIZE
@@ -667,6 +678,7 @@ typedef union {
#define Conv_cnote_ss_flags_buf_t Conv32_cnote_ss_flags_buf_t
#define Conv_cnote_cc_content_buf_t Conv32_cnote_cc_content_buf_t
#define Conv_cnote_auxv_af_buf_t Conv32_cnote_auxv_af_buf_t
+#define Conv_ver_flags_buf_t Conv32_ver_flags_buf_t
#endif
@@ -860,7 +872,8 @@ extern void conv_str_to_c_literal(const char *buf, size_t n,
Conv_str_to_c_literal_func_t *cb_func,
void *uvalue);
extern Uts_desc *conv_uts(void);
-extern const char *conv_ver_flags(Half);
+extern const char *conv_ver_flags(Half, Conv_fmt_flags_t,
+ Conv_ver_flags_buf_t *);
extern const char *conv_ver_index(Versym, int, Conv_inv_buf_t *);
diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h
index bc0ed3a9bc..334ff1e3b3 100644
--- a/usr/src/cmd/sgs/include/libld.h
+++ b/usr/src/cmd/sgs/include/libld.h
@@ -965,6 +965,8 @@ struct ver_desc {
struct ver_index {
const char *vi_name; /* dependency version name */
Half vi_flags; /* communicates availability */
+ Half vi_overndx; /* Index asssigned to this version in */
+ /* output object Verneed section */
Ver_desc *vi_desc; /* cross reference to descriptor */
};
@@ -976,10 +978,10 @@ struct ver_index {
#define FLG_VER_AVAIL 0x10 /* version is available for binding */
#define FLG_VER_REFER 0x20 /* version has been referenced */
-#define FLG_VER_SELECT 0x40 /* version has been selected by user */
+#define FLG_VER_SPECVER 0x40 /* via $SPECVERS in mapfile. */
+ /* Cannot be normalized away */
#define FLG_VER_CYCLIC 0x80 /* a member of cyclic dependency */
-
/*
* isalist(1) descriptor - used to break an isalist string into its component
* options.
diff --git a/usr/src/cmd/sgs/lari/lari.pl b/usr/src/cmd/sgs/lari/lari.pl
index fff5d3f045..c398bd3590 100644
--- a/usr/src/cmd/sgs/lari/lari.pl
+++ b/usr/src/cmd/sgs/lari/lari.pl
@@ -21,11 +21,9 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# Link Analysis of Runtime Interfaces.
#
@@ -1201,7 +1199,6 @@ sub GetAllSymbols {
my ($Type, $FileHandle);
my (%AddrToName, %NameToAddr);
my ($Exec) = 0;
- my ($Vers) = 0;
my ($Symb) = 0;
my ($Copy) = 0;
my ($Interpose) = 0;
@@ -1233,12 +1230,13 @@ sub GetAllSymbols {
# -e ELF header provides the file type
# -d dynamic information provides filter names
# -r relocations provide for copy relocations
+ # -v object versioning
# -y symbol information section provide pre-symbol filters
# and direct binding information
#
# As this information can be quite large, process the elfdump(1) output
# through a pipe.
- open($FileHandle, "LC_ALL=C elfdump -edry '$Obj' 2> /dev/null |");
+ open($FileHandle, "LC_ALL=C elfdump -edrvy '$Obj' 2> /dev/null |");
while (defined(my $Line = <$FileHandle>)) {
my (@Fields);
@@ -1261,6 +1259,12 @@ sub GetAllSymbols {
} elsif ($Line =~ /^Syminfo Section:/) {
$Info = 1;
$Ehdr = $Dyn = $Rel = 0;
+ } elsif ($Line =~ /^Version Definition Section:/) {
+ # The existance of a VERDEF section is all we
+ # are looking for. There is no need to parse
+ # the specific version definitions.
+ $Versioned{$Obj} = 1;
+ $Ehdr = $Dyn = $Rel = $Info = 0;
} else {
$Ehdr = $Dyn = $Rel = $Info = 0;
}
@@ -1509,13 +1513,6 @@ sub GetAllSymbols {
$Symbols{$Fields[8]}{$Obj}[$ObjFlag] |= $Flags;
$Symbols{$Fields[8]}{$Obj}[$ObjVis] = $Fields[5];
$Objects{$Obj}{$Fields[8]} |= $Flags;
-
- # If the version field is non-null this object has already been
- # versioned.
- if (($Vers == 0) && ($Fields[6] ne '0')) {
- $Versioned{$Obj} = 1;
- $Vers = 1;
- }
}
close($FileHandle);
diff --git a/usr/src/cmd/sgs/libconv/common/llib-lconv b/usr/src/cmd/sgs/libconv/common/llib-lconv
index 64fb7017a2..0ba1cbe236 100644
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv
@@ -26,8 +26,6 @@
/* LINTLIBRARY */
/* PROTOLIB1 */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <libelf.h>
#include <_machelf.h>
@@ -57,7 +55,7 @@ const char *conv_lddstub(int);
const char *conv_seg_flags(Half, Conv_seg_flags_buf_t *);
int conv_sys_eclass(void);
Uts_desc *conv_uts(void);
-const char *conv_ver_flags(Half);
+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/version.c b/usr/src/cmd/sgs/libconv/common/version.c
index 6b3fe924d3..087bfe6951 100644
--- a/usr/src/cmd/sgs/libconv/common/version.c
+++ b/usr/src/cmd/sgs/libconv/common/version.c
@@ -20,10 +20,9 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* String conversion routine for version flag entries.
@@ -32,15 +31,48 @@
#include "_conv.h"
#include "version_msg.h"
+#define VERFLAGSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+ MSG_VER_FLG_WEAK_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_VER_FLG_BASE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_VER_FLG_INFO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_ver_flags_buf_t is large enough:
+ *
+ * VERFLAGSZ is the real minimum size of the buffer required by
+ * conv_ver_flags(). However, Conv_ver_flags_buf_t uses CONV_VER_FLAGS_BUFSIZE
+ * to set the buffer size. We do things this way because the definition of
+ * VERFLAGSZ uses information that is not available in the environment of
+ * other programs that include the conv.h header file.
+ */
+#if (CONV_VER_FLAGS_BUFSIZE != VERFLAGSZ) && !defined(__lint)
+#define REPORT_BUFSIZE VERFLAGSZ
+#include "report_bufsize.h"
+#error "CONV_VER_FLAGS_BUFSIZE does not match VERFLAGSZ"
+#endif
+
const char *
-conv_ver_flags(Half flags)
+conv_ver_flags(Half flags, Conv_fmt_flags_t fmt_flags,
+ Conv_ver_flags_buf_t *ver_flags_buf)
{
- if (flags & VER_FLG_WEAK)
- return (MSG_ORIG(MSG_VER_FLG_WEAK));
- else if (flags & VER_FLG_BASE)
- return (MSG_ORIG(MSG_VER_FLG_BASE));
- else
+ static Val_desc vda[] = {
+ { VER_FLG_WEAK, MSG_ORIG(MSG_VER_FLG_WEAK) },
+ { VER_FLG_BASE, MSG_ORIG(MSG_VER_FLG_BASE) },
+ { VER_FLG_INFO, MSG_ORIG(MSG_VER_FLG_INFO) },
+ { 0, 0 }
+ };
+ static CONV_EXPN_FIELD_ARG conv_arg = {
+ NULL, sizeof (ver_flags_buf->buf), vda };
+
+ if (flags == 0)
return (MSG_ORIG(MSG_GBL_NULL));
+
+ conv_arg.buf = ver_flags_buf->buf;
+ conv_arg.oflags = conv_arg.rflags = flags;
+ (void) conv_expn_field(&conv_arg, fmt_flags);
+
+ return ((const char *)ver_flags_buf->buf);
}
diff --git a/usr/src/cmd/sgs/libconv/common/version.msg b/usr/src/cmd/sgs/libconv/common/version.msg
index 465fac840d..f04ee75c2d 100644
--- a/usr/src/cmd/sgs/libconv/common/version.msg
+++ b/usr/src/cmd/sgs/libconv/common/version.msg
@@ -1,5 +1,5 @@
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -21,12 +21,11 @@
#
# CDDL HEADER END
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# Message file for cmd/sgs/libconv/common/versions.c
-@ MSG_VER_FLG_WEAK "[ WEAK ]"
-@ MSG_VER_FLG_BASE "[ BASE ]"
+@ MSG_VER_FLG_WEAK "WEAK"
+@ MSG_VER_FLG_BASE "BASE"
+@ MSG_VER_FLG_INFO "INFO"
@ MSG_VERSYM_ELIMINATE "ELIM"
diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c
index 0472ceadec..46d1c81d18 100644
--- a/usr/src/cmd/sgs/libld/common/sections.c
+++ b/usr/src/cmd/sgs/libld/common/sections.c
@@ -2659,16 +2659,17 @@ ld_make_sections(Ofl_desc *ofl)
/*
* Add any necessary versioning information.
*/
- if ((flags & (FLG_OF_VERNEED | FLG_OF_NOVERSEC)) == FLG_OF_VERNEED) {
- if (make_verneed(ofl) == S_ERROR)
+ if (!(flags & FLG_OF_NOVERSEC)) {
+ if ((flags & FLG_OF_VERNEED) &&
+ (make_verneed(ofl) == S_ERROR))
return (S_ERROR);
- }
- if ((flags & (FLG_OF_VERDEF | FLG_OF_NOVERSEC)) == FLG_OF_VERDEF) {
- if (make_verdef(ofl) == S_ERROR)
+ if ((flags & FLG_OF_VERDEF) &&
+ (make_verdef(ofl) == S_ERROR))
return (S_ERROR);
- if ((ofl->ofl_osversym = make_sym_sec(ofl,
+ if ((flags & (FLG_OF_VERNEED | FLG_OF_VERDEF)) &&
+ ((ofl->ofl_osversym = make_sym_sec(ofl,
MSG_ORIG(MSG_SCN_SUNWVERSYM), SHT_SUNW_versym,
- ld_targ.t_id.id_version)) == (Os_desc*)S_ERROR)
+ ld_targ.t_id.id_version)) == (Os_desc*)S_ERROR))
return (S_ERROR);
}
diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c
index d33ee869c4..b3b1da69b9 100644
--- a/usr/src/cmd/sgs/libld/common/update.c
+++ b/usr/src/cmd/sgs/libld/common/update.c
@@ -303,7 +303,8 @@ update_osym(Ofl_desc *ofl)
* table. There is one entry for each symbol which contains the symbols
* version index.
*/
- if ((flags & (FLG_OF_VERDEF | FLG_OF_NOVERSEC)) == FLG_OF_VERDEF) {
+ if (!(flags & FLG_OF_NOVERSEC) &&
+ (flags & (FLG_OF_VERNEED | FLG_OF_VERDEF))) {
versym = (Versym *)ofl->ofl_osversym->os_outdata->d_buf;
versym[0] = 0;
} else
@@ -1188,9 +1189,9 @@ update_osym(Ofl_desc *ofl)
if (sdp->sd_symndx && versym) {
Half vndx = 0;
- if (sdp->sd_flags & FLG_SY_MVTOCOMM)
+ if (sdp->sd_flags & FLG_SY_MVTOCOMM) {
vndx = VER_NDX_GLOBAL;
- else if (sdp->sd_ref == REF_REL_NEED) {
+ } else if (sdp->sd_ref == REF_REL_NEED) {
Half symflags1 = sdp->sd_flags1;
vndx = sap->sa_overndx;
@@ -1201,6 +1202,13 @@ update_osym(Ofl_desc *ofl)
else
vndx = VER_NDX_GLOBAL;
}
+ } else if ((sdp->sd_ref == REF_DYN_NEED) &&
+ (sap->sa_dverndx > 0) &&
+ (sap->sa_dverndx <= sdp->sd_file->ifl_vercnt) &&
+ (sdp->sd_file->ifl_verndx != NULL)) {
+ /* Use index of verneed record */
+ vndx = sdp->sd_file->ifl_verndx
+ [sap->sa_dverndx].vi_overndx;
}
versym[sdp->sd_symndx] = vndx;
}
@@ -2467,7 +2475,7 @@ update_overdef(Ofl_desc *ofl)
Ver_desc *vdp, *_vdp;
Verdef *vdf, *_vdf;
int num = 0;
- Os_desc *strosp, *symosp;
+ Os_desc *strosp;
/*
* Traverse the version descriptors and update the version structures
@@ -2572,15 +2580,11 @@ update_overdef(Ofl_desc *ofl)
if ((ofl->ofl_flags & FLG_OF_RELOBJ) ||
(ofl->ofl_flags & FLG_OF_STATIC)) {
strosp = ofl->ofl_osstrtab;
- symosp = ofl->ofl_ossymtab;
} else {
strosp = ofl->ofl_osdynstr;
- symosp = ofl->ofl_osdynsym;
}
/* LINTED */
ofl->ofl_osverdef->os_shdr->sh_link = (Word)elf_ndxscn(strosp->os_scn);
- /* LINTED */
- ofl->ofl_osversym->os_shdr->sh_link = (Word)elf_ndxscn(symosp->os_scn);
/*
* The version definition sections `info' field is used to indicate the
@@ -2592,6 +2596,33 @@ update_overdef(Ofl_desc *ofl)
}
/*
+ * Finish the version symbol index section
+ */
+static int
+update_oversym(Ofl_desc *ofl)
+{
+ Os_desc *symosp;
+
+ /*
+ * Record the string table association with the version definition
+ * section, and the symbol table associated with the version symbol
+ * table (the actual contents of the version symbol table are filled
+ * in during symbol update).
+ */
+ if ((ofl->ofl_flags & FLG_OF_RELOBJ) ||
+ (ofl->ofl_flags & FLG_OF_STATIC)) {
+ symosp = ofl->ofl_ossymtab;
+ } else {
+ symosp = ofl->ofl_osdynsym;
+ }
+
+ /* LINTED */
+ ofl->ofl_osversym->os_shdr->sh_link = (Word)elf_ndxscn(symosp->os_scn);
+
+ return (1);
+}
+
+/*
* Build the version needed section
*/
static int
@@ -2601,7 +2632,8 @@ update_overneed(Ofl_desc *ofl)
Ifl_desc *ifl;
Verneed *vnd, *_vnd;
Str_tbl *dynstr;
- Word num = 0, cnt = 0;
+ Word num = 0;
+ int has_specver;
dynstr = ofl->ofl_dynstrtab;
_vnd = vnd = (Verneed *)ofl->ofl_osverneed->os_outdata->d_buf;
@@ -2612,6 +2644,7 @@ update_overneed(Ofl_desc *ofl)
*/
for (LIST_TRAVERSE(&ofl->ofl_sos, lnp, ifl)) {
Half _cnt;
+ Word cnt = 0;
Vernaux *_vnap, *vnap;
Sdf_desc *sdf = ifl->ifl_sdfdesc;
size_t stoff;
@@ -2626,16 +2659,25 @@ update_overneed(Ofl_desc *ofl)
_vnap = vnap = (Vernaux *)(vnd + 1);
- if (sdf && (sdf->sdf_flags & FLG_SDF_SPECVER)) {
+ has_specver = sdf && (sdf->sdf_flags & FLG_SDF_SPECVER);
+ if (has_specver) {
Sdv_desc *sdv;
Listnode *lnp2;
/*
* If version needed definitions were specified in
- * a mapfile ($VERSION=*) then record those
+ * a mapfile ($SPECVERS=*) then record those
* definitions.
*/
for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2, sdv)) {
+ /*
+ * If this $SPECVERS item corresponds
+ * to a real version, then skip it here
+ * in favor of the real one below.
+ */
+ if (sdv->sdv_flags & FLG_SDV_MATCHED)
+ continue;
+
(void) st_setstring(dynstr, sdv->sdv_name,
&stoff);
vnap->vna_name = stoff;
@@ -2650,41 +2692,62 @@ update_overneed(Ofl_desc *ofl)
_vnap->vna_next = (Word)((uintptr_t)vnap -
(uintptr_t)_vnap);
}
- } else {
+ }
- /*
- * Traverse the version index list recording
- * each version as a needed dependency.
- */
- for (cnt = _cnt = 0; _cnt <= ifl->ifl_vercnt;
- _cnt++) {
- Ver_index *vip = &ifl->ifl_verndx[_cnt];
-
- if (vip->vi_flags & FLG_VER_REFER) {
- (void) st_setstring(dynstr,
- vip->vi_name, &stoff);
- vnap->vna_name = stoff;
-
- if (vip->vi_desc) {
- vnap->vna_hash =
- vip->vi_desc->vd_hash;
- vnap->vna_flags =
- vip->vi_desc->vd_flags;
- } else {
- vnap->vna_hash = 0;
- vnap->vna_flags = 0;
- }
- vnap->vna_other = 0;
+ /*
+ * Traverse the version index list recording
+ * each version as a needed dependency.
+ */
+ for (_cnt = 0; _cnt <= ifl->ifl_vercnt; _cnt++) {
+ Ver_index *vip = &ifl->ifl_verndx[_cnt];
- _vnap = vnap;
- vnap++, cnt++;
- _vnap->vna_next =
- /* LINTED */
- (Word)((uintptr_t)vnap -
- (uintptr_t)_vnap);
+ if (vip->vi_flags & FLG_VER_REFER) {
+ (void) st_setstring(dynstr, vip->vi_name,
+ &stoff);
+ vnap->vna_name = stoff;
+
+ if (vip->vi_desc) {
+ vnap->vna_hash = vip->vi_desc->vd_hash;
+ vnap->vna_flags =
+ vip->vi_desc->vd_flags;
+ } else {
+ vnap->vna_hash = 0;
+ vnap->vna_flags = 0;
}
+ vnap->vna_other = vip->vi_overndx;
+
+ /*
+ * If version A inherits version B, then
+ * B is implicit in A. It suffices for ld.so.1
+ * to verify A at runtime and skip B. The
+ * version normalization process sets the INFO
+ * flag for the versions we want ld.so.1 to
+ * skip. By default, we progagate these flags
+ * to the output object as computed.
+ *
+ * The presence of $SPECVERS items alters
+ * matters. If $SPECVERS are present in the
+ * mapfile, then any version that corresponds
+ * to the $SPECVERS must be validated, and
+ * all others must be skipped. This is true
+ * even if it causes ld.so.1 to incorrectly
+ * validate the object ---- it is an override
+ * mechanism.
+ */
+ if ((!has_specver &&
+ (vip->vi_flags & VER_FLG_INFO)) ||
+ (has_specver &&
+ !(vip->vi_flags & FLG_VER_SPECVER)))
+ vnap->vna_flags |= VER_FLG_INFO;
+
+ _vnap = vnap;
+ vnap++, cnt++;
+ _vnap->vna_next =
+ /* LINTED */
+ (Word)((uintptr_t)vnap - (uintptr_t)_vnap);
}
}
+
_vnap->vna_next = 0;
/*
@@ -3753,12 +3816,17 @@ ld_update_outfile(Ofl_desc *ofl)
*/
if (update_oehdr(ofl) == S_ERROR)
return (S_ERROR);
- if ((flags & (FLG_OF_VERDEF | FLG_OF_NOVERSEC)) == FLG_OF_VERDEF)
- if (update_overdef(ofl) == S_ERROR)
+ if (!(flags & FLG_OF_NOVERSEC)) {
+ if ((flags & FLG_OF_VERDEF) &&
+ (update_overdef(ofl) == S_ERROR))
+ return (S_ERROR);
+ if ((flags & FLG_OF_VERNEED) &&
+ (update_overneed(ofl) == S_ERROR))
return (S_ERROR);
- if ((flags & (FLG_OF_VERNEED | FLG_OF_NOVERSEC)) == FLG_OF_VERNEED)
- if (update_overneed(ofl) == S_ERROR)
+ if ((flags & (FLG_OF_VERNEED | FLG_OF_VERDEF)) &&
+ (update_oversym(ofl) == S_ERROR))
return (S_ERROR);
+ }
if (flags & FLG_OF_DYNAMIC) {
if (update_odynamic(ofl) == S_ERROR)
return (S_ERROR);
diff --git a/usr/src/cmd/sgs/libld/common/version.c b/usr/src/cmd/sgs/libld/common/version.c
index 65f84a6035..6365addc27 100644
--- a/usr/src/cmd/sgs/libld/common/version.c
+++ b/usr/src/cmd/sgs/libld/common/version.c
@@ -20,10 +20,9 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <stdio.h>
@@ -313,12 +312,17 @@ vers_derefer(Ifl_desc *ifl, Ver_desc *vdp, int weak)
Ver_index *vip = &ifl->ifl_verndx[vdp->vd_ndx];
/*
- * If the head of the list was a weak then we only clear out
+ * Set the INFO bit on all dependencies that ld.so.1
+ * can skip verification for. These are the dependencies
+ * that are inherited by others -- verifying the inheriting
+ * version implicitily covers this one.
+ *
+ * If the head of the list was a weak then we only mark
* weak dependencies, but if the head of the list was 'strong'
- * we clear the REFER bit on all dependencies.
+ * we set INFO on all dependencies.
*/
if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
- vip->vi_flags &= ~FLG_VER_REFER;
+ vip->vi_flags |= VER_FLG_INFO;
for (LIST_TRAVERSE(&vdp->vd_deps, lnp, _vdp))
vers_derefer(ifl, _vdp, weak);
@@ -334,6 +338,15 @@ ld_vers_check_need(Ofl_desc *ofl)
{
Listnode *lnp1;
Ifl_desc *ifl;
+ Half needndx;
+
+ /*
+ * Versym indexes for needed versions start with the next
+ * available version after the final definied version.
+ * However, it can never be less than 2. 0 is always for local
+ * scope, and 1 is always the first global definition.
+ */
+ needndx = (ofl->ofl_vercnt > 0) ? (ofl->ofl_vercnt + 1) : 2;
/*
* Traverse the shared object list looking for dependencies.
@@ -343,7 +356,7 @@ ld_vers_check_need(Ofl_desc *ofl)
Ver_index *vip;
Ver_desc *vdp;
Sdf_desc *sdf = ifl->ifl_sdfdesc;
- Byte cnt, need;
+ Byte cnt, need = 0;
if (!(ifl->ifl_flags & FLG_IF_NEEDED))
continue;
@@ -353,23 +366,30 @@ ld_vers_check_need(Ofl_desc *ofl)
/*
* If version needed definitions were specified in
- * a mapfile ($SPECVERS=) then record those definitions
+ * a mapfile ($SPECVERS=) then record those definitions.
*/
if (sdf && (sdf->sdf_flags & FLG_SDF_SPECVER)) {
Sdv_desc *sdv;
for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2,
sdv)) {
+
+ /*
+ * If this $SPECVERS item corresponds to
+ * a real version, then don't issue it
+ * here, but use the real one instead.
+ * This preserves the ability to reference it
+ * from a symbol versym entry.
+ */
+ if (sdv->sdv_flags & FLG_SDV_MATCHED)
+ continue;
+
+ /* Not found in known versions. Count it */
ofl->ofl_verneedsz += sizeof (Vernaux);
if (st_insert(ofl->ofl_dynstrtab,
sdv->sdv_name) == -1)
return (S_ERROR);
+ need++;
}
- ifl->ifl_flags |= FLG_IF_VERNEED;
- ofl->ofl_verneedsz += sizeof (Verneed);
- if (st_insert(ofl->ofl_dynstrtab,
- ifl->ifl_soname) == -1)
- return (S_ERROR);
- continue;
}
/*
@@ -379,7 +399,7 @@ ld_vers_check_need(Ofl_desc *ofl)
* cause fatal errors from the runtime linker, non-weak
* dependencies do.
*/
- for (need = 0, cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
+ for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
vip = &ifl->ifl_verndx[cnt];
vdp = vip->vi_desc;
@@ -421,7 +441,7 @@ ld_vers_check_need(Ofl_desc *ofl)
* Finally, determine how many of the version dependencies need
* to be recorded.
*/
- for (need = 0, cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
+ for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
vip = &ifl->ifl_verndx[cnt];
/*
@@ -429,6 +449,9 @@ ld_vers_check_need(Ofl_desc *ofl)
* version dependency.
*/
if (vip->vi_flags & FLG_VER_REFER) {
+ /* Assign a VERSYM index for it */
+ vip->vi_overndx = needndx++;
+
ofl->ofl_verneedsz += sizeof (Vernaux);
if (st_insert(ofl->ofl_dynstrtab,
vip->vi_name) == -1)
@@ -513,15 +536,20 @@ vers_index(Ofl_desc *ofl, Ifl_desc *ifl, int avail)
if (vdp->vd_flags & VER_FLG_WEAK)
vip[ndx].vi_flags |= VER_FLG_WEAK;
/*
- * If this version is mentioned in a mapfile
- * $ADDVERS syntax then add a FLG_IF_NEEDED flag now
+ * If this version is mentioned in a mapfile using
+ * $ADDVERS or $SPECVERS syntax then check to see if
+ * it corresponds to an actual version in the file.
*/
- if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
+ if (sdf &&
+ (sdf->sdf_flags & (FLG_SDF_SPECVER|FLG_SDF_ADDVER))) {
Listnode * lnp2;
for (LIST_TRAVERSE(&sdf->sdf_verneed, lnp2, sdv)) {
if (strcmp(vip[ndx].vi_name,
sdv->sdv_name) == 0) {
vip[ndx].vi_flags |= FLG_VER_REFER;
+ if (sdf->sdf_flags & FLG_SDF_SPECVER)
+ vip[ndx].vi_flags |=
+ FLG_VER_SPECVER;
sdv->sdv_flags |= FLG_SDV_MATCHED;
break;
}
diff --git a/usr/src/cmd/sgs/liblddbg/common/version.c b/usr/src/cmd/sgs/liblddbg/common/version.c
index 914d5d11ec..b61758dd68 100644
--- a/usr/src/cmd/sgs/liblddbg/common/version.c
+++ b/usr/src/cmd/sgs/liblddbg/common/version.c
@@ -20,10 +20,9 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <debug.h>
@@ -109,10 +108,11 @@ Dbg_ver_nointerface(Lm_list *lml, const char *name)
void
Dbg_ver_desc_entry(Lm_list *lml, Ver_desc *vdp)
{
- const char *dep;
- Ver_desc *_vdp, *__vdp;
- Listnode * lnp;
- char index[10];
+ Conv_ver_flags_buf_t ver_flags_buf;
+ const char *dep;
+ Ver_desc *_vdp, *__vdp;
+ Listnode *lnp;
+ char index[10];
if (DBG_NOTCLASS(DBG_C_VERSIONS))
return;
@@ -126,7 +126,7 @@ Dbg_ver_desc_entry(Lm_list *lml, Ver_desc *vdp)
}
(void) sprintf(index, MSG_ORIG(MSG_FMT_INDEX), vdp->vd_ndx);
Elf_ver_line_1(lml, index, vdp->vd_name, dep,
- conv_ver_flags(vdp->vd_flags));
+ conv_ver_flags(vdp->vd_flags, 0, &ver_flags_buf));
/*
* Loop through the dependency list in case there are more that one
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index d5ad09bd9d..ae3266f2d0 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1378,3 +1378,5 @@ Bugid Risk Synopsis
PSARC 2008/583 add gld options to ld(1)
6746674 setuid applications do not find libraries any more because trusted
directories behavior changed
+6749055 ld should generate GNU style VERSYM indexes for VERNEED records
+ PSARC/2008/603 ELF objects to adopt GNU-style Versym indexes
diff --git a/usr/src/cmd/sgs/pvs/Makefile.com b/usr/src/cmd/sgs/pvs/Makefile.com
index 969646160f..b082ec7f6e 100644
--- a/usr/src/cmd/sgs/pvs/Makefile.com
+++ b/usr/src/cmd/sgs/pvs/Makefile.com
@@ -20,11 +20,9 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
PROG= pvs
@@ -34,7 +32,9 @@ include $(SRC)/cmd/sgs/Makefile.com
COMOBJ= pvs.o
BLTOBJ= msg.o
-OBJS= $(BLTOBJ) $(COMOBJ)
+TOOLOBJS = alist.o
+
+OBJS= $(BLTOBJ) $(COMOBJ) $(TOOLOBJS)
MAPFILE= $(MAPFILE.NGB)
MAPOPTS= $(MAPFILE:%=-M%)
@@ -60,7 +60,8 @@ SGSMSGALL= $(SGSMSGCOM)
SGSMSGFLAGS += -h $(BLTDEFS) -d $(BLTDATA) -m $(BLTMESG) -n pvs_msg
-SRCS= $(COMOBJ:%.o=../common/%.c) $(BLTDATA)
+SRCS= $(COMOBJ:%.o=../common/%.c) $(BLTDATA) \
+ $(TOOLOBJS:%.o=$(SGSTOOLS)/common/%.c)
LINTSRCS= $(SRCS) ../common/lintsup.c
CLEANFILES += $(LINTOUTS) $(BLTFILES)
diff --git a/usr/src/cmd/sgs/pvs/Makefile.targ b/usr/src/cmd/sgs/pvs/Makefile.targ
index 4922b7ca29..e7a49190c9 100644
--- a/usr/src/cmd/sgs/pvs/Makefile.targ
+++ b/usr/src/cmd/sgs/pvs/Makefile.targ
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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.
@@ -20,15 +19,18 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright (c) 2001 by Sun Microsystems, Inc.
-# All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
%.o: ../common/%.c
$(COMPILE.c) $<
$(POST_PROCESS_O)
+%.o: $(SGSTOOLS)/common/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
all: $(PROG)
clean:
diff --git a/usr/src/cmd/sgs/pvs/common/lintsup.c b/usr/src/cmd/sgs/pvs/common/lintsup.c
index 12a83f0706..1cb5cfba78 100644
--- a/usr/src/cmd/sgs/pvs/common/lintsup.c
+++ b/usr/src/cmd/sgs/pvs/common/lintsup.c
@@ -22,10 +22,9 @@
/* PROTOLIB1 */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Supplimental Pseudo-code to get lint to consider
@@ -39,4 +38,12 @@ void
foo()
{
dbg_print(0, _pvs_msg((Msg)&__pvs_msg[0]));
+
+ alist_delete_by_offset(NULL, NULL);
+ (void) alist_insert_by_offset(NULL, NULL, 0, 0, 0);
+ alist_reset(NULL);
+
+ (void) aplist_delete_value(NULL, NULL);
+ aplist_reset(NULL);
+ (void) aplist_test(NULL, NULL, 0);
}
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.c b/usr/src/cmd/sgs/pvs/common/pvs.c
index cc8cb42a8d..2ef648fc14 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.c
+++ b/usr/src/cmd/sgs/pvs/common/pvs.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Analyze the versioning information within a file.
*
@@ -33,7 +31,7 @@
*
* -d dump version definitions.
*
- * -l print reduced (local) symbols.
+ * -l print reduced (local) symbols. Implies -s.
*
* -n normalize any version definitions.
*
@@ -46,8 +44,11 @@
*
* -v verbose output. With the -r and -d options any WEAK attribute
* is displayed. With the -d option, any version inheritance,
- * and the base version are displayed. With the -s option the
- * version symbol is displayed.
+ * and the base version are displayed. With the -r option,
+ * WEAK and INFO attributes are displayed. With the -s option
+ * the version symbol is displayed.
+ *
+ * -I index only print the specifed version index, or index range.
*
* -N name only print the specifed `name'.
*/
@@ -64,9 +65,15 @@
#include <conv.h>
#include <gelf.h>
#include <debug.h>
+#include <ctype.h>
+#include <alist.h>
#include "msg.h"
-#define FLG_VER_AVAIL 0x10
+/*
+ * Define Alist initialization sizes.
+ */
+#define AL_CNT_MATCH_LIST 5 /* match_list initial alist count */
+#define AL_CNT_GVER_DESC 25 /* version tracking descriptors */
typedef struct cache {
Elf_Scn *c_scn;
@@ -79,21 +86,70 @@ typedef struct gver_desc {
unsigned long vd_hash;
GElf_Half vd_ndx;
GElf_Half vd_flags;
- List vd_deps;
+ APlist *vd_deps;
} GVer_desc;
+/* Versym related data used by gvers_syms() */
+typedef struct {
+ GElf_Versym *vsd_vsp; /* ptr to versym data */
+ Elf_Data *vsd_sym_data; /* ptr to symtab data */
+ Word vsd_symn; /* # of symbols in symtab */
+ const char *vsd_strs; /* string table data */
+} Gver_sym_data;
+
+/*
+ * Type used to manage -I and -N options:
+ *
+ * The -I option specifies a VERSYM index, or index range. The
+ * result is to select the VERDEF or VERNEED records with
+ * indexes that match those given.
+ *
+ * -N options come in two forms:
+ *
+ * 1) name
+ * 2) needobj (version)
+ *
+ * The meaning of the first case depends on the type of
+ * version record being matched:
+ *
+ * VERDEF - name is the name of a version defined
+ * by the object being processed (i.e. SUNW_1.1).
+ *
+ * VERNEED - name is the name of the object file
+ * on which the dependency exists (i.e. libc.so.1).
+ *
+ * -N options of the second form only apply to VERNEED records.
+ * They are used to specify a version from a needed object.
+ */
+/* match_opt_t is used to note which match option was used */
+typedef enum {
+ MATCH_OPT_NAME, /* Record contains a name */
+ MATCH_OPT_NEED_VER, /* Record contains needed object and version */
+ MATCH_OPT_NDX, /* Record contains a single index */
+ MATCH_OPT_RANGE, /* Record contains an index range */
+} match_opt_t;
+
+typedef struct {
+ match_opt_t opt_type;
+ union {
+ struct {
+ const char *version; /* MATCH_OPT_{NAME|NEED_VER} */
+ const char *needobj; /* MATCH_OPT_NEED_VER only */
+ } name;
+ struct {
+ int start; /* MATCH_OPT_{NDX|RANGE} */
+ int end; /* MATCH_OPT_RANGE only) */
+ } ndx;
+ } value;
+} match_rec_t;
+
+
+
static const char *cname;
static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag;
+static Alist *match_list;
-static const char
- * Format_ofil = "%s -",
- * Format_tnco = "\t%s:\n",
- * Format_tnse = "\t%s;\n",
- * Format_bgnl = "\t%s (%s",
- * Format_next = ", %s",
- * Format_weak = " [WEAK]",
- * Format_endl = ");\n";
-
+/* Used to track whether an option defaulted to on, or was explicitly set */
#define DEF_DEFINED 1
#define USR_DEFINED 2
@@ -110,6 +166,305 @@ demangle(const char *name)
}
/*
+ * Append an item to the specified list, and return a pointer to the list
+ * node created.
+ *
+ * exit:
+ * On success, a new list node is created and the item is
+ * added to the list. On failure, a fatal error is issued
+ * and the process exits.
+ */
+static void
+pvs_aplist_append(APlist **lst, const void *item, const char *file)
+{
+ if (aplist_append(lst, item, AL_CNT_GVER_DESC) == NULL) {
+ int err = errno;
+ (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file,
+ strerror(err));
+ exit(1);
+ }
+}
+
+/*
+ * Add an entry to match_list for use by match(). This routine is for
+ * use during getopt() processing.
+ *
+ * entry:
+ * opt - One of 'N' or 'I', indicating the option
+ * str - Value string corresponding to opt
+ *
+ * exit:
+ * The new match record has been added. On error, a fatal
+ * error is issued and and the process exits.
+ */
+static void
+add_match_record(int opt, const char *str)
+{
+ /*
+ * Macros for removing leading and trailing whitespace:
+ * WS_SKIP - Advance _str without passing the NULL termination,
+ * until the first character is not whitespace.
+ * WS_SKIP_LIMIT - Advance _str without passing _limit,
+ * until the first character is not whitespace.
+ * WS_RSKIP_LIMIT - Move _tail back without passing _str,
+ * until the character before it is not whitespace.
+ * Write a NULL termination at that point.
+ */
+#define WS_SKIP(_str) for (; *(_str) && isspace(*(_str)); (_str)++)
+#define WS_SKIP_LIMIT(_str, _limit) \
+ while (((_str) < s2) && isspace(*(_str))) \
+ (_str)++
+#define WS_RSKIP_LIMIT(_str, _tail) \
+ while (((_tail) > (_str)) && isspace(*((_tail) - 1))) \
+ (_tail)--; \
+ *(_tail) = '\0'
+
+
+ match_rec_t *rec;
+ char *lstr, *s1, *s2;
+
+ rec = alist_append(&match_list, NULL, sizeof (match_rec_t),
+ AL_CNT_MATCH_LIST);
+ if (rec == NULL) {
+ int err = errno;
+ (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
+ MSG_INTL(MSG_STR_MATCH_RECORD), strerror(err));
+ exit(1);
+ }
+
+ if (opt == 'N') {
+ if ((lstr = strdup(str)) == NULL) {
+ int err = errno;
+ (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
+ cname, MSG_INTL(MSG_STR_MATCH_RECORD),
+ strerror(err));
+ exit(1);
+ }
+
+ /* Strip leading/trailing whitespace */
+ s2 = lstr + strlen(lstr);
+ WS_SKIP_LIMIT(lstr, s2);
+ WS_RSKIP_LIMIT(lstr, s2);
+
+ /* Assume this is a plain string */
+ rec->opt_type = MATCH_OPT_NAME;
+ rec->value.name.version = lstr;
+
+ /*
+ * If s2 points at a closing paren, then this might
+ * be a MATCH_OPT_NEED_VER case. Otherwise we're done.
+ */
+ if ((s2 == lstr) || (*(s2 - 1) != ')'))
+ return;
+
+ /* We have a closing paren. Locate the opening one. */
+ for (s1 = lstr; *s1 && (*s1 != '('); s1++)
+ ;
+ if (*s1 != '(')
+ return;
+
+ rec->opt_type = MATCH_OPT_NEED_VER;
+ rec->value.name.needobj = lstr;
+ rec->value.name.version = s1 + 1;
+ s2--; /* Points at closing paren */
+
+ /* Remove whitespace from head/tail of version */
+ WS_SKIP_LIMIT(rec->value.name.version, s2);
+ WS_RSKIP_LIMIT(rec->value.name.version, s2);
+
+ /* Terminate needobj, skipping trailing whitespace */
+ WS_RSKIP_LIMIT(rec->value.name.needobj, s1);
+
+ return;
+ }
+
+
+ /* If we get here, we are looking at a -I index option */
+ rec->value.ndx.start = strtol(str, &s2, 10);
+ /* Value must use some of the input, and be positive */
+ if ((str == s2) || (rec->value.ndx.start < 1))
+ goto syntax_error;
+ str = s2;
+
+ WS_SKIP(str);
+ if (*str != ':') {
+ rec->opt_type = MATCH_OPT_NDX;
+ } else {
+ str++; /* Skip the ':' */
+ rec->opt_type = MATCH_OPT_RANGE;
+ WS_SKIP(str);
+ if (*str == '\0') {
+ rec->value.ndx.end = -1; /* Indicates "to end" */
+ } else {
+ rec->value.ndx.end = strtol(str, &s2, 10);
+ if ((str == s2) || (rec->value.ndx.end < 0))
+ goto syntax_error;
+ str = s2;
+ WS_SKIP(str);
+ }
+ }
+
+ /* If we are successful, there is nothing left to parse */
+ if (*str == '\0')
+ return;
+
+ /*
+ * If we get here, there is leftover input. Fall through
+ * to issue a syntax error.
+ */
+syntax_error:
+ (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname);
+ exit(1);
+
+#undef WS_SKIP
+#undef WS_SKIP_LIMIT
+#undef WS_RSKIP_LIMIT
+}
+
+/*
+ * Returns True (1) if the version with the given name or index should
+ * be displayed, and False (0) if it should not be.
+ *
+ * entry:
+ * needobj - NULL for VERDEF records, the name of the
+ * needed object for VERNEED.
+ * version - NULL, or needed version
+ * ndx - Versym index of version under consideration, or a value less
+ * than 1 to indicate that no valid index is given.
+ *
+ * exit:
+ * True will be returned if the given name/index matches those given
+ * by one of the -I or -N command line options, or if no such option
+ * was used in the command invocation.
+ */
+int
+match(const char *needobj, const char *version, int ndx)
+{
+ Aliste _idx;
+ match_rec_t *rec;
+ const char *str;
+
+ /* If there is no match list, then we approve everything */
+ if (alist_nitems(match_list) == 0)
+ return (1);
+
+ /* Run through the match records and check for a hit */
+ for (ALIST_TRAVERSE(match_list, _idx, rec)) {
+ switch (rec->opt_type) {
+ case MATCH_OPT_NAME:
+ if (needobj)
+ str = needobj;
+ else if (version)
+ str = version;
+ else
+ break;
+ if (strcmp(rec->value.name.version, str) == 0)
+ return (1);
+ break;
+ case MATCH_OPT_NEED_VER:
+ if (needobj && version &&
+ (strcmp(rec->value.name.needobj, needobj) == 0) &&
+ (strcmp(rec->value.name.version, version) == 0))
+ return (1);
+ break;
+ case MATCH_OPT_NDX:
+ if ((ndx > 0) && (ndx == rec->value.ndx.start))
+ return (1);
+ break;
+ case MATCH_OPT_RANGE:
+ /*
+ * A range end value less than 0 means that any value
+ * above the start is acceptible.
+ */
+ if ((ndx > 0) &&
+ (ndx >= rec->value.ndx.start) &&
+ ((rec->value.ndx.end < 0) ||
+ (ndx <= rec->value.ndx.end)))
+ return (1);
+ break;
+ }
+ }
+
+ /* Nothing matched */
+ return (0);
+}
+
+/*
+ * List the symbols that belong to a specified version
+ *
+ * entry:
+ * vsdata - VERSYM related data from the object
+ * vd_ndx - The VERSYM index for symbols to display
+ * vd_name - Version name
+ * needobj - NULL for symbols corresponding to a VERDEF
+ * record. Name of the needed object in the case
+ * of a VERNEED record.
+ * file - Object file
+ */
+static void
+gvers_syms(const Gver_sym_data *vsdata, GElf_Half vd_ndx,
+ const char *vd_name, const char *needobj, const char *file)
+{
+ GElf_Sym sym;
+ int _symn;
+
+ for (_symn = 0; _symn < vsdata->vsd_symn; _symn++) {
+ size_t size = 0;
+ const char *name;
+
+ if (vsdata->vsd_vsp[_symn] != vd_ndx)
+ continue;
+
+ (void) gelf_getsym(vsdata->vsd_sym_data, _symn, &sym);
+ name = demangle(vsdata->vsd_strs + sym.st_name);
+
+ /*
+ * Symbols that reference a VERDEF record
+ * have some extra details to handle.
+ */
+ if (needobj == NULL) {
+ /*
+ * For data symbols defined by this object,
+ * determine the size.
+ */
+ if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) ||
+ (GELF_ST_TYPE(sym.st_info) == STT_COMMON) ||
+ (GELF_ST_TYPE(sym.st_info) == STT_TLS))
+ size = (size_t)sym.st_size;
+
+ /*
+ * Only output the version symbol when the verbose
+ * flag is used.
+ */
+ if (!vflag && (sym.st_shndx == SHN_ABS) &&
+ (strcmp(name, vd_name) == 0))
+ continue;
+ }
+
+ if (oflag) {
+ if (needobj == NULL)
+ (void) printf(MSG_ORIG(MSG_FMT_SYM_OFIL),
+ file, vd_name);
+ else
+ (void) printf(MSG_ORIG(MSG_FMT_SYM_NEED_OFIL),
+ file, needobj, vd_name);
+
+ if (size)
+ (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ_OFLG),
+ name, (ulong_t)size);
+ else
+ (void) printf(MSG_ORIG(MSG_FMT_SYM_OFLG), name);
+ } else {
+ if (size)
+ (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ), name,
+ (ulong_t)size);
+ else
+ (void) printf(MSG_ORIG(MSG_FMT_SYM), name);
+ }
+ }
+}
+
+/*
* Print any reduced symbols. The convention is that reduced symbols exist as
* LOCL entries in the .symtab, between the FILE symbol for the output file and
* the first FILE symbol for any input file used to build the output file.
@@ -120,7 +475,7 @@ sym_local(Cache *cache, Cache *csym, const char *file)
int symn, _symn, found = 0;
GElf_Shdr shdr;
GElf_Sym sym;
- char *strs, *local = "_LOCAL_";
+ char *strs;
(void) gelf_getshdr(csym->c_scn, &shdr);
strs = (char *)cache[shdr.sh_link].c_data->d_buf;
@@ -162,29 +517,49 @@ sym_local(Cache *cache, Cache *csym, const char *file)
name = demangle(strs + sym.st_name);
if (oflag) {
- (void) printf(Format_ofil, file);
- (void) printf("\t%s: %s\n", local, name);
+ (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_OFLG),
+ file, name);
} else {
if (found == 0) {
found = 1;
- (void) printf(Format_tnco, local);
+ (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_HDR));
}
- (void) printf("\t\t%s;\n", name);
+ (void) printf(MSG_ORIG(MSG_FMT_LOCSYM), name);
}
}
}
/*
- * Print the files version needed sections.
+ * Print data from the files VERNEED section.
+ *
+ * If we have been asked to display symbols, then the
+ * output format follows that used for verdef sections,
+ * with each version displayed separately. For instance:
+ *
+ * libc.so.1 (SUNW_1.7):
+ * sym1;
+ * sym2;
+ * libc.so.1 (SUNW_1.9):
+ * sym3;
+ *
+ * If we are not displaying symbols, then a terse format
+ * is used, which combines all the needed versions from
+ * a given object into a single line. In this case, the
+ * versions are shown whether or not they contribute symbols.
+ *
+ * libc.so.1 (SUNW_1.7, SUNW_1.9);
*/
static int
-gvers_need(Cache *cache, Cache *need, const char *file, const char *name)
+gvers_need(Cache *cache, Cache *need, const Gver_sym_data *vsdata,
+ const char *file)
{
unsigned int num, _num;
char *strs;
GElf_Verneed *vnd = need->c_data->d_buf;
GElf_Shdr shdr;
int error = 0;
+ int show = vflag || (vsdata == NULL) || !oflag;
+
(void) gelf_getshdr(need->c_scn, &shdr);
@@ -205,107 +580,144 @@ gvers_need(Cache *cache, Cache *need, const char *file, const char *name)
for (_num = 1; _num <= num; _num++,
vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
- GElf_Vernaux *vnap = (GElf_Vernaux *)
- ((uintptr_t)vnd + vnd->vn_aux);
- GElf_Half cnt = vnd->vn_cnt;
- const char *_name, * dep;
+ GElf_Vernaux *vnap;
+ Word ndx;
+ const char *needobj, *dep, *fmt;
+ int started = 0;
- /*
- * Obtain the version name and determine if we need to process
- * it further.
- */
- _name = (char *)(strs + vnd->vn_file);
- if (name && (strcmp(name, _name) == 0))
- continue;
+ vnap = (GElf_Vernaux *) ((uintptr_t)vnd + vnd->vn_aux);
+
+ /* Obtain the needed object file name */
+ needobj = (char *)(strs + vnd->vn_file);
error = 1;
- /*
- * If one-line ouput is called for display the filename being
- * processed.
- */
- if (oflag)
- (void) printf(Format_ofil, file);
+ /* Process the versions needed from this object */
+ for (ndx = 0; ndx < vnd->vn_cnt; ndx++,
+ vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
+ Conv_ver_flags_buf_t ver_flags_buf;
- /*
- * Determine the version name required from this file.
- */
- if (cnt--)
dep = (char *)(strs + vnap->vna_name);
- else
- dep = MSG_ORIG(MSG_STR_EMPTY);
- (void) printf(Format_bgnl, _name, dep);
- if (vflag && (vnap->vna_flags == VER_FLG_WEAK))
- (void) printf(Format_weak);
+ if (!match(needobj, dep, vnap->vna_other))
+ continue;
- /*
- * Extract any other version dependencies for this file
- */
- /* CSTYLED */
- for (vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next);
- cnt; cnt--,
- vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
- dep = (char *)(strs + vnap->vna_name);
- (void) printf(Format_next, dep);
- if (vflag && (vnap->vna_flags == VER_FLG_WEAK))
- (void) printf(Format_weak);
+ if (show) {
+ if ((started == 0) || (vsdata != NULL)) {
+ /*
+ * If one-line ouput is called for
+ * display the filename being processed.
+ */
+ if (oflag && show)
+ (void) printf(
+ MSG_ORIG(MSG_FMT_OFIL),
+ file);
+
+ (void) printf(
+ MSG_ORIG(MSG_FMT_LIST_BEGIN),
+ needobj);
+
+ fmt = MSG_ORIG(MSG_FMT_LIST_FIRST);
+ started = 1;
+ } else {
+ fmt = MSG_ORIG(MSG_FMT_LIST_NEXT);
+ }
+
+ /*
+ * If not showing symbols, only show INFO
+ * versions in verbose mode. They don't
+ * actually contribute to the version
+ * interface as seen by rtld, so listing them
+ * without qualification can be misleading.
+ */
+ if (vflag || (vsdata != NULL) ||
+ (alist_nitems(match_list) != 0) ||
+ !(vnap->vna_flags & VER_FLG_INFO)) {
+ (void) printf(fmt, dep);
+
+ /* Show non-zero flags */
+ if (vflag && (vnap->vna_flags != 0))
+ (void) printf(
+ MSG_ORIG(MSG_FMT_VER_FLG),
+ conv_ver_flags(
+ vnap->vna_flags,
+ CONV_FMT_NOBKT,
+ &ver_flags_buf));
+ }
+ if (vsdata != NULL)
+ (void) printf(oflag ?
+ MSG_ORIG(MSG_FMT_LIST_END_SEM) :
+ MSG_ORIG(MSG_FMT_LIST_END_COL));
+ }
+
+ /*
+ * If we are showing symbols, and vna_other is
+ * non-zero, list them here.
+ *
+ * A value of 0 means that this object uses
+ * traditional Solaris versioning rules, under
+ * which VERSYM does not contain indexes to VERNEED
+ * records. In this case, there is nothing to show.
+ */
+ if (vsdata && (vnap->vna_other > 0))
+ gvers_syms(vsdata, vnap->vna_other,
+ dep, needobj, file);
}
- (void) printf(Format_endl);
+ if (show && started && (vsdata == NULL))
+ (void) printf(MSG_ORIG(MSG_FMT_LIST_END_SEM));
}
return (error);
}
/*
- * Append an item to the specified list, and return a pointer to the list
- * node created.
+ * Return a GVer_desc descriptor for the given version if one
+ * exists.
+ *
+ * entry:
+ * name - Version name
+ * hash - ELF hash of name
+ * lst - APlist of existing descriptors.
+ * file - Object file containing the version
+ *
+ * exit:
+ * Return the corresponding GVer_desc struct if it
+ * exists, and NULL otherwise.
*/
-static Listnode *
-list_append(List *lst, const void *item, const char *file)
-{
- Listnode *_lnp;
-
- if ((_lnp = malloc(sizeof (Listnode))) == 0) {
- int err = errno;
- (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file,
- strerror(err));
- exit(1);
- }
-
- _lnp->data = (void *)item;
- _lnp->next = NULL;
-
- if (lst->head == NULL)
- lst->tail = lst->head = _lnp;
- else {
- lst->tail->next = _lnp;
- lst->tail = lst->tail->next;
- }
- return (_lnp);
-}
-
static GVer_desc *
-gvers_find(const char *name, unsigned long hash, List *lst)
+gvers_find(const char *name, unsigned long hash, APlist *lst)
{
- Listnode *lnp;
+ Aliste idx;
GVer_desc *vdp;
- for (LIST_TRAVERSE(lst, lnp, vdp)) {
- if (vdp->vd_hash != hash)
- continue;
- if (strcmp(vdp->vd_name, name) == 0)
+ for (APLIST_TRAVERSE(lst, idx, vdp))
+ if ((vdp->vd_hash == hash) &&
+ (strcmp(vdp->vd_name, name) == 0))
return (vdp);
- }
- return (0);
+
+ return (NULL);
}
+/*
+ * Return a GVer_desc descriptor for the given version.
+ *
+ * entry:
+ * name - Version name
+ * hash - ELF hash of name
+ * lst - List of existing descriptors.
+ * file - Object file containing the version
+ *
+ * exit:
+ * Return the corresponding GVer_desc struct. If the
+ * descriptor does not already exist, it is created.
+ * On error, a fatal error is issued and the process exits.
+ */
static GVer_desc *
-gvers_desc(const char *name, unsigned long hash, List *lst, const char *file)
+gvers_desc(const char *name, unsigned long hash, APlist **lst, const char *file)
{
GVer_desc *vdp;
- if ((vdp = gvers_find(name, hash, lst)) == 0) {
- if ((vdp = calloc(sizeof (GVer_desc), 1)) == 0) {
+ if ((vdp = gvers_find(name, hash, *lst)) == NULL) {
+ if ((vdp = calloc(sizeof (GVer_desc), 1)) == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
file, strerror(err));
@@ -315,83 +727,44 @@ gvers_desc(const char *name, unsigned long hash, List *lst, const char *file)
vdp->vd_name = name;
vdp->vd_hash = hash;
- if (list_append(lst, vdp, file) == 0)
- return (0);
+ pvs_aplist_append(lst, vdp, file);
}
return (vdp);
}
+/*
+ * Insert a version dependency for the given GVer_desc descriptor.
+ *
+ * entry:
+ * name - Dependency version name
+ * hash - ELF hash of name
+ * lst - List of existing descriptors.
+ * vdp - Existing version descriptor to which the dependency
+ * is to be added.
+ * file - Object file containing the version
+ *
+ * exit:
+ * A descriptor for the dependency version is looked up
+ * (created if necessary), and then added to the dependency
+ * list for vdp. Returns the dependency descriptor. On error,
+ * a fatal error is issued and the process exits.
+ */
static GVer_desc *
-gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, List *lst,
+gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, APlist **lst,
const char *file)
{
GVer_desc *_vdp;
- if ((_vdp = gvers_desc(name, hash, lst, file)) == 0)
- return (0);
-
- if (list_append(&vdp->vd_deps, _vdp, file) == 0)
- return (0);
-
+ _vdp = gvers_desc(name, hash, lst, file);
+ pvs_aplist_append(&vdp->vd_deps, _vdp, file);
return (vdp);
}
static void
-gvers_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs,
- GVer_desc *vdp, const char *file)
-{
- GElf_Sym sym;
- int _symn;
-
- for (_symn = 0; _symn < symn; _symn++) {
- size_t size = 0;
- const char *name;
-
- if (vsp[_symn] != vdp->vd_ndx)
- continue;
-
- /*
- * For data symbols determine the size.
- */
- (void) gelf_getsym(sym_data, _symn, &sym);
- if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) ||
- (GELF_ST_TYPE(sym.st_info) == STT_COMMON) ||
- (GELF_ST_TYPE(sym.st_info) == STT_TLS))
- size = (size_t)sym.st_size;
-
- name = demangle(strs + sym.st_name);
-
- /*
- * Only output the version symbol when the verbose flag is used.
- */
- if (!vflag && (sym.st_shndx == SHN_ABS)) {
- if (strcmp(name, vdp->vd_name) == 0)
- continue;
- }
-
- if (oflag) {
- (void) printf(Format_ofil, file);
- (void) printf("\t%s: ", vdp->vd_name);
- if (size)
- (void) printf("%s (%ld);\n", name,
- (ulong_t)size);
- else
- (void) printf("%s;\n", name);
- } else {
- if (size)
- (void) printf("\t\t%s (%ld);\n", name,
- (ulong_t)size);
- else
- (void) printf("\t\t%s;\n", name);
- }
- }
-}
-
-static void
-gvers_derefer(GVer_desc * vdp, int weak)
+gvers_derefer(GVer_desc *vdp, int weak)
{
- Listnode * _lnp;
- GVer_desc * _vdp;
+ Aliste idx;
+ GVer_desc *_vdp;
/*
* If the head of the list was a weak then we only clear out
@@ -401,24 +774,23 @@ gvers_derefer(GVer_desc * vdp, int weak)
if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
vdp->vd_flags &= ~FLG_VER_AVAIL;
- for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp))
+ for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp))
gvers_derefer(_vdp, weak);
}
static void
-recurse_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs,
- GVer_desc *vdp, const char *file)
+recurse_syms(const Gver_sym_data *vsdata, GVer_desc *vdp, const char *file)
{
- Listnode *_lnp;
+ Aliste idx;
GVer_desc *_vdp;
- for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) {
+ for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) {
if (!oflag)
- (void) printf(Format_tnco, _vdp->vd_name);
- gvers_syms(vsp, sym_data, symn, strs, _vdp, file);
- if (_vdp->vd_deps.head)
- recurse_syms(vsp, sym_data, symn, strs, _vdp, file);
+ (void) printf(MSG_ORIG(MSG_FMT_TNCO), _vdp->vd_name);
+ gvers_syms(vsdata, _vdp->vd_ndx, _vdp->vd_name, NULL, file);
+ if (aplist_nitems(_vdp->vd_deps) != 0)
+ recurse_syms(vsdata, _vdp, file);
}
}
@@ -427,19 +799,16 @@ recurse_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs,
* Print the files version definition sections.
*/
static int
-gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
- const char *name)
+gvers_def(Cache *cache, Cache *def, const Gver_sym_data *vsdata,
+ const char *file)
{
unsigned int num, _num;
char *strs;
- GElf_Versym *vsp;
GElf_Verdef *vdf = def->c_data->d_buf;
GElf_Shdr shdr;
- Elf_Data *sym_data;
- int symn;
- GVer_desc *vdp, *bvdp = 0;
- Listnode *lnp;
- List verdefs = {0, 0};
+ GVer_desc *vdp, *bvdp = NULL;
+ Aliste idx1;
+ APlist *verdefs = NULL;
int error = 0;
/*
@@ -467,18 +836,17 @@ gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
GElf_Half cnt = vdf->vd_cnt;
GElf_Half ndx = vdf->vd_ndx;
- GElf_Verdaux *vdap = (GElf_Verdaux *)((uintptr_t)vdf +
- vdf->vd_aux);
+ GElf_Verdaux *vdap;
const char *_name;
+ vdap = (GElf_Verdaux *)((uintptr_t)vdf + vdf->vd_aux);
+
/*
* Determine the version name and any dependencies.
*/
_name = (char *)(strs + vdap->vda_name);
- if ((vdp = gvers_desc(_name, elf_hash(_name), &verdefs,
- file)) == 0)
- return (0);
+ vdp = gvers_desc(_name, elf_hash(_name), &verdefs, file);
vdp->vd_ndx = ndx;
vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL;
@@ -487,7 +855,7 @@ gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
_name = (char *)(strs + vdap->vda_name);
if (gvers_depend(_name, elf_hash(_name), vdp,
- &verdefs, file) == 0)
+ &verdefs, file) == NULL)
return (0);
}
@@ -502,12 +870,12 @@ gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
* Normalize the dependency list if required.
*/
if (nflag) {
- for (LIST_TRAVERSE(&verdefs, lnp, vdp)) {
- Listnode * _lnp;
- GVer_desc * _vdp;
+ for (APLIST_TRAVERSE(verdefs, idx1, vdp)) {
+ Aliste idx2;
+ GVer_desc *_vdp;
int type = vdp->vd_flags & VER_FLG_WEAK;
- for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp))
+ for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp))
gvers_derefer(_vdp, type);
}
@@ -523,15 +891,15 @@ gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
* Traverse the dependency list and print out the appropriate
* information.
*/
- for (LIST_TRAVERSE(&verdefs, lnp, vdp)) {
- Listnode * _lnp;
- GVer_desc * _vdp;
+ for (APLIST_TRAVERSE(verdefs, idx1, vdp)) {
+ Aliste idx2;
+ GVer_desc *_vdp;
int count;
- if (name && (strcmp(name, vdp->vd_name) != 0))
+ if (!match(NULL, vdp->vd_name, vdp->vd_ndx))
continue;
-
- if (!name && !(vdp->vd_flags & FLG_VER_AVAIL))
+ if ((alist_nitems(match_list) == 0) &&
+ !(vdp->vd_flags & FLG_VER_AVAIL))
continue;
error = 1;
@@ -543,77 +911,86 @@ gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
* dependencies this version inherits.
*/
if (oflag)
- (void) printf(Format_ofil, file);
- (void) printf("\t%s", vdp->vd_name);
- if (vdp->vd_flags & VER_FLG_WEAK)
- (void) printf(Format_weak);
+ (void) printf(MSG_ORIG(MSG_FMT_OFIL), file);
+ (void) printf(MSG_ORIG(MSG_FMT_VER_NAME), vdp->vd_name);
+ if ((vdp->vd_flags & MSK_VER_USER) != 0) {
+ Conv_ver_flags_buf_t ver_flags_buf;
+
+ (void) printf(MSG_ORIG(MSG_FMT_VER_FLG),
+ conv_ver_flags(
+ vdp->vd_flags & MSK_VER_USER,
+ CONV_FMT_NOBKT, &ver_flags_buf));
+ }
count = 1;
- for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) {
+ for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) {
const char *_name = _vdp->vd_name;
if (count++ == 1) {
+
if (oflag)
- (void) printf(": {%s", _name);
+ (void) printf(
+ MSG_ORIG(MSG_FMT_IN_OFLG),
+ _name);
else if (vdp->vd_flags & VER_FLG_WEAK)
- (void) printf(":\t{%s", _name);
+ (void) printf(
+ MSG_ORIG(MSG_FMT_IN_WEAK),
+ _name);
else
- (void) printf(": \t{%s",
+ (void) printf(
+ MSG_ORIG(MSG_FMT_IN),
_name);
} else
- (void) printf(Format_next, _name);
+ (void) printf(
+ MSG_ORIG(MSG_FMT_LIST_NEXT), _name);
}
if (count != 1)
- (void) printf("}");
+ (void) printf(MSG_ORIG(MSG_FMT_IN_END));
- if (csym && !oflag)
- (void) printf(":\n");
+ if (vsdata && !oflag)
+ (void) printf(MSG_ORIG(MSG_FMT_COL_NL));
else
- (void) printf(";\n");
+ (void) printf(MSG_ORIG(MSG_FMT_SEM_NL));
} else {
- if (csym && !oflag)
- (void) printf(Format_tnco, vdp->vd_name);
- else if (!csym) {
+ if (vsdata && !oflag)
+ (void) printf(MSG_ORIG(MSG_FMT_TNCO),
+ vdp->vd_name);
+ else if (!vsdata) {
if (oflag)
- (void) printf(Format_ofil, file);
- (void) printf(Format_tnse, vdp->vd_name);
+ (void) printf(MSG_ORIG(MSG_FMT_OFIL),
+ file);
+ (void) printf(MSG_ORIG(MSG_FMT_TNSE),
+ vdp->vd_name);
}
}
- /*
- * If we need to print symbols get the associated symbol table.
- */
- if (csym) {
- (void) gelf_getshdr(csym->c_scn, &shdr);
- vsp = (GElf_Versym *)csym->c_data->d_buf;
- sym_data = cache[shdr.sh_link].c_data;
- (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr);
- /* LINTED */
- symn = (int)(shdr.sh_size / shdr.sh_entsize);
- } else
+ /* If we are not printing symbols, we're done */
+ if (vsdata == NULL)
continue;
/*
- * If a specific version name has been specified then display
- * any of its own symbols plus any inherited from other
- * versions. Otherwise simply print out the symbols for this
- * version.
+ * If a specific version to match has been specified then
+ * display any of its own symbols plus any inherited from
+ * other versions. Otherwise simply print out the symbols
+ * for this version.
*/
- gvers_syms(vsp, sym_data, symn, strs, vdp, file);
- if (name) {
- recurse_syms(vsp, sym_data, symn, strs, vdp, file);
+ gvers_syms(vsdata, vdp->vd_ndx, vdp->vd_name, NULL, file);
+ if (alist_nitems(match_list) != 0) {
+ recurse_syms(vsdata, vdp, file);
/*
- * If the verbose flag is set add the base version as a
- * dependency (unless it's the list we were asked to
- * print in the first place).
+ * If the verbose flag is set, and this is not
+ * the base version, then add the base version as a
+ * dependency.
*/
- if (vflag && bvdp && strcmp(name, bvdp->vd_name)) {
+ if (vflag && bvdp &&
+ !match(NULL, bvdp->vd_name, bvdp->vd_ndx)) {
if (!oflag)
- (void) printf(Format_tnco, bvdp->vd_name);
- gvers_syms(vsp, sym_data, symn, strs, bvdp,
- file);
+ (void) printf(MSG_ORIG(MSG_FMT_TNCO),
+ bvdp->vd_name);
+ gvers_syms(vsdata, bvdp->vd_ndx,
+ bvdp->vd_name, NULL, file);
}
}
}
@@ -629,11 +1006,12 @@ main(int argc, char **argv, char **envp)
Elf_Data *data;
GElf_Ehdr ehdr;
int nfile, var;
- const char *name;
char *names;
Cache *cache, *_cache;
Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc;
int error = 0;
+ Gver_sym_data vsdata_s;
+ const Gver_sym_data *vsdata = NULL;
/*
* Check for a binary that better fits this architecture.
@@ -647,11 +1025,10 @@ main(int argc, char **argv, char **envp)
(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
cname = argv[0];
- name = NULL;
Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0;
opterr = 0;
- while ((var = getopt(argc, argv, "CdlnorsvN:")) != EOF) {
+ while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
switch (var) {
case 'C':
Cflag = USR_DEFINED;
@@ -660,7 +1037,7 @@ main(int argc, char **argv, char **envp)
dflag = USR_DEFINED;
break;
case 'l':
- lflag = USR_DEFINED;
+ lflag = sflag = USR_DEFINED;
break;
case 'n':
nflag = USR_DEFINED;
@@ -677,8 +1054,9 @@ main(int argc, char **argv, char **envp)
case 'v':
vflag = USR_DEFINED;
break;
+ case 'I':
case 'N':
- name = optarg;
+ add_match_record(var, optarg);
break;
case '?':
(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
@@ -701,7 +1079,7 @@ main(int argc, char **argv, char **envp)
/*
* By default print both version definitions and needed dependencies.
*/
- if ((dflag == 0) && (rflag == 0))
+ if ((dflag == 0) && (rflag == 0) && (lflag == 0))
dflag = rflag = DEF_DEFINED;
/*
@@ -774,14 +1152,14 @@ main(int argc, char **argv, char **envp)
* as elf_begin has already gone through all the overhead we
* might as well set up the cache for every section.
*/
- if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == 0) {
+ if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == NULL) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
file, strerror(err));
exit(1);
}
- _cache_def = _cache_need = _cache_sym = _cache_loc = 0;
+ _cache_def = _cache_need = _cache_sym = _cache_loc = NULL;
_cache = cache;
_cache++;
for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) {
@@ -830,7 +1208,7 @@ main(int argc, char **argv, char **envp)
* Before printing anything out determine if any warnings are
* necessary.
*/
- if (lflag && (_cache_loc == 0)) {
+ if (lflag && (_cache_loc == NULL)) {
(void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS),
cname, file);
(void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB));
@@ -841,20 +1219,36 @@ main(int argc, char **argv, char **envp)
* one-line output, display the filename being processed.
*/
if ((nfile > 1) && !oflag)
- (void) printf("%s:\n", file);
+ (void) printf(MSG_ORIG(MSG_FMT_FILE), file);
+
+ /*
+ * If we're printing symbols, then collect the data
+ * necessary to do that.
+ */
+ if (_cache_sym != NULL) {
+ vsdata = &vsdata_s;
+ (void) gelf_getshdr(_cache_sym->c_scn, &shdr);
+ vsdata_s.vsd_vsp =
+ (GElf_Versym *)_cache_sym->c_data->d_buf;
+ vsdata_s.vsd_sym_data = cache[shdr.sh_link].c_data;
+ (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr);
+ vsdata_s.vsd_symn = shdr.sh_size / shdr.sh_entsize;
+ vsdata_s.vsd_strs =
+ (const char *)cache[shdr.sh_link].c_data->d_buf;
+ }
+
/*
* Print the files version needed sections.
*/
if (_cache_need)
- nerror = gvers_need(cache, _cache_need, file, name);
+ nerror = gvers_need(cache, _cache_need, vsdata, file);
/*
* Print the files version definition sections.
*/
if (_cache_def)
- derror = gvers_def(cache, _cache_def, _cache_sym,
- file, name);
+ derror = gvers_def(cache, _cache_def, vsdata, file);
/*
* Print any local symbol reductions.
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.msg b/usr/src/cmd/sgs/pvs/common/pvs.msg
index ef3c2256f1..30883b3336 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.msg
+++ b/usr/src/cmd/sgs/pvs/common/pvs.msg
@@ -20,10 +20,9 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
@ _START_
@@ -34,9 +33,10 @@
# Argument usage messages.
-@ MSG_USAGE_BRIEF "usage: %s [-Cdlnorsv] [-N Name] file(s)\n"
+@ MSG_USAGE_BRIEF "usage: %s [-Cdlnorsv] [-I index] [-N Name] file(s)\n"
@ MSG_USAGE_DETAIL "\t[-C]\t\tdemangle C++ symbol names\n\
\t[-d]\t\tprint version definition information\n\
+ \t[-I index]\tqualify version with an index\n\
\t[-l]\t\tprint reduced symbols\n\
\t[-N name]\tqualify version with `name'\n\
\t[-n]\t\tnormalize version definition information\n\
@@ -64,6 +64,7 @@
@ MSG_SYS_OPEN "%s: %s: cannot open file: %s\n"
@ MSG_SYS_MALLOC "%s: %s: malloc failed: %s\n"
+@ MSG_STR_MATCH_RECORD "match record (-I/-N)"
@ _END_
@@ -78,5 +79,37 @@
@ MSG_ELF_GETDATA "%s: %s: elf_getdata: %s\n"
@ MSG_STR_EMPTY ""
+@ MSG_STR_OPTIONS "CdI:lnorsvN:"
+
+@ MSG_FMT_COL_NL ":\n"
+@ MSG_FMT_SEM_NL ";\n"
+@ MSG_FMT_LIST_BEGIN "\t%s ("
+@ MSG_FMT_LIST_FIRST "%s"
+@ MSG_FMT_LIST_NEXT ", %s"
+@ MSG_FMT_LIST_END_SEM ");\n"
+@ MSG_FMT_LIST_END_COL "):\n"
+@ MSG_FMT_OFIL "%s -"
+@ MSG_FMT_TNCO "\t%s:\n"
+@ MSG_FMT_TNSE "\t%s;\n"
+@ MSG_FMT_VER_NAME "\t%s"
+@ MSG_FMT_VER_FLG " [%s]"
+
+@ MSG_FMT_FILE "%s:\n"
+
+@ MSG_FMT_SYM_OFIL "%s -\t%s: "
+@ MSG_FMT_SYM_NEED_OFIL "%s -\t%s (%s): "
+@ MSG_FMT_SYM_OFLG "%s;\n"
+@ MSG_FMT_SYM_SZ_OFLG "%s (%ld);\n"
+@ MSG_FMT_SYM "\t\t%s;\n"
+@ MSG_FMT_SYM_SZ "\t\t%s (%ld);\n"
+
+@ MSG_FMT_IN ": \t{%s"
+@ MSG_FMT_IN_OFLG ": {%s"
+@ MSG_FMT_IN_WEAK ":\t{%s"
+@ MSG_FMT_IN_END "}"
+
+@ MSG_FMT_LOCSYM_HDR "\t_LOCAL_:\n"
+@ MSG_FMT_LOCSYM "\t\t%s;\n"
+@ MSG_FMT_LOCSYM_OFLG "%s -\t_LOCAL_: %s\n"
@ MSG_SUNW_OST_SGS "SUNW_OST_SGS"
diff --git a/usr/src/cmd/sgs/rtld/common/elf.c b/usr/src/cmd/sgs/rtld/common/elf.c
index 5cae84bdeb..6d86c460cf 100644
--- a/usr/src/cmd/sgs/rtld/common/elf.c
+++ b/usr/src/cmd/sgs/rtld/common/elf.c
@@ -29,8 +29,6 @@
* All Rights Reserved
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Object file dependent support for ELF objects.
*/
@@ -518,6 +516,19 @@ elf_verify_vers(const char *name, Rt_map *clmp, Rt_map *nlmp)
ulong_t _num, num = VERDEFNUM(nlmp);
int found = 0;
+ /*
+ * Skip validation of versions that are marked
+ * INFO. This optimization is used for versions
+ * that are inherited by another version. Verification
+ * of the inheriting version is sufficient.
+ *
+ * Such versions are recorded in the object for the
+ * benefit of VERSYM entries that refer to them. This
+ * provides a purely diagnositic benefit.
+ */
+ if (vnap->vna_flags & VER_FLG_INFO)
+ continue;
+
version = (char *)(cstrs + vnap->vna_name);
DBG_CALL(Dbg_ver_need_entry(lml, 0, need, version));