diff options
| author | rie <none@none> | 2007-11-29 08:50:31 -0800 |
|---|---|---|
| committer | rie <none@none> | 2007-11-29 08:50:31 -0800 |
| commit | a194faf8907a6722dcf10ad16c6ca72c9b7bd0ba (patch) | |
| tree | d24cfdf302395bb6cbc356d2192c9e42ba7951ea /usr | |
| parent | 7a6460b615cb8a60e3de57d76ba619a0a253ff74 (diff) | |
| download | illumos-joyent-a194faf8907a6722dcf10ad16c6ca72c9b7bd0ba.tar.gz | |
6629404 ld with -z ignore doesn't scale
Diffstat (limited to 'usr')
20 files changed, 653 insertions, 548 deletions
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c index 0bb56ca130..e19f5f7a8c 100644 --- a/usr/src/cmd/sgs/elfdump/common/elfdump.c +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c @@ -33,6 +33,7 @@ #include <sys/elf_amd64.h> #include <sys/elf_SPARC.h> #include <dwarf.h> +#include <stdio.h> #include <unistd.h> #include <errno.h> #include <strings.h> @@ -42,7 +43,6 @@ #include <_elfdump.h> - /* * VERSYM_STATE is used to maintain information about the VERSYM section * in the object being analyzed. It is filled in by versions(), and used diff --git a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c index 6484f48bce..f6f6d6eb25 100644 --- a/usr/src/cmd/sgs/elfdump/common/fake_shdr.c +++ b/usr/src/cmd/sgs/elfdump/common/fake_shdr.c @@ -63,6 +63,7 @@ #include <machdep.h> #include <sys/elf_amd64.h> +#include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> diff --git a/usr/src/cmd/sgs/include/_string_table.h b/usr/src/cmd/sgs/include/_string_table.h new file mode 100644 index 0000000000..de0955ec58 --- /dev/null +++ b/usr/src/cmd/sgs/include/_string_table.h @@ -0,0 +1,126 @@ +/* + * 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 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef __STRING_TABLE_DOT_H +#define __STRING_TABLE_DOT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/avl.h> +#include <string_table.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A string is represented in a string table using two values: length, and + * value. Grouping all the strings of a given length together allows for + * efficient matching of tail strings, as each input string value is hashed. + * Each string table uses a 2-level AVL tree of AVL trees to represent this + * organization. + * + * The outer (main) AVL tree contains LenNode structures. The search key for + * nodes on this main tree is the string length. Each such node represents + * all strings of a given length, and all strings of that length are found + * within. + * + * The strings within each LenNode are maintained using a secondary AVL tree + * of StrNode structures. The search key for this inner tree is the string + * itself. The strings are maintained in lexical order. + */ +typedef struct { + avl_node_t sn_avlnode; /* AVL book-keeping */ + const char *sn_str; /* string */ + uint_t sn_refcnt; /* reference count */ +} StrNode; + +typedef struct { + avl_node_t ln_avlnode; /* AVL book-keeping */ + avl_tree_t *ln_strtree; /* AVL tree of associated strings */ + uint_t ln_strlen; /* length of associated strings */ +} LenNode; + +/* + * Define a master string data item. Other strings may be suffixes of this + * string. The final string table will consist of the master string values, + * laid end to end, with the other strings referencing their tails. + */ +typedef struct str_master Str_master; + +struct str_master { + const char *sm_str; /* pointer to master string */ + Str_master *sm_next; /* used for tracking master strings */ + uint_t sm_strlen; /* length of master string */ + uint_t sm_hashval; /* hashval of master string */ + uint_t sm_stroff; /* offset into destination strtab */ +}; + +/* + * Define a hash data item. This item represents an individual string that has + * been input into the String hash table. The string may either be a suffix of + * another string, or a master string. + */ +typedef struct str_hash Str_hash; + +struct str_hash { + uint_t hi_strlen; /* string length */ + uint_t hi_refcnt; /* number of references to str */ + uint_t hi_hashval; /* hash for string */ + Str_master *hi_mstr; /* pointer to master string */ + Str_hash *hi_next; /* next entry in hash bucket */ +}; + +/* + * Controlling data structure for a String Table. + */ +struct str_tbl { + avl_tree_t *st_lentree; /* AVL tree of string lengths */ + char *st_strbuf; /* string buffer */ + Str_hash **st_hashbcks; /* hash buckets */ + Str_master *st_mstrlist; /* list of all master strings */ + uint_t st_fullstrsize; /* uncompressed table size */ + uint_t st_nextoff; /* next available string */ + uint_t st_strsize; /* compressed size */ + uint_t st_strcnt; /* number of strings */ + uint_t st_hbckcnt; /* number of buckets in */ + /* hashlist */ + uint_t st_flags; +}; + +#define FLG_STTAB_COMPRESS 0x01 /* compressed string table */ +#define FLG_STTAB_COOKED 0x02 /* offset has been assigned */ + +/* + * Starting value for use with string hashing functions inside of string_table.c + */ +#define HASHSEED 5381 + +#ifdef __cplusplus +} +#endif + +#endif /* __STRING_TABLE_DOT_H */ diff --git a/usr/src/cmd/sgs/include/debug.h b/usr/src/cmd/sgs/include/debug.h index b777961190..bb77b596d4 100644 --- a/usr/src/cmd/sgs/include/debug.h +++ b/usr/src/cmd/sgs/include/debug.h @@ -786,7 +786,7 @@ extern void Dbg_syms_ar_resolve(Lm_list *, Xword, Elf_Arsym *, const char *, int); extern void Dbg_syms_ar_title(Lm_list *, const char *, int); extern void Dbg_syms_created(Lm_list *, const char *); -extern void Dbg_syms_discarded(Lm_list *, Sym_desc *, Is_desc *); +extern void Dbg_syms_discarded(Lm_list *, Sym_desc *); extern void Dbg_syms_dlsym(Rt_map *, const char *, const char *, int); extern void Dbg_syms_dup_sort_addr(Lm_list *, const char *, const char *, const char *, Addr); diff --git a/usr/src/cmd/sgs/include/string_table.h b/usr/src/cmd/sgs/include/string_table.h index 433ca394e2..1bd2d383e2 100644 --- a/usr/src/cmd/sgs/include/string_table.h +++ b/usr/src/cmd/sgs/include/string_table.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,109 +28,33 @@ #pragma ident "%Z%%M% %I% %E% SMI" -#include <stdio.h> #include <sys/types.h> -#include <sys/avl.h> -#include <sgs.h> #ifdef __cplusplus extern "C" { #endif -typedef struct str_hash Str_hash; -typedef struct str_tbl Str_tbl; -typedef struct str_master Str_master; - - -/* - * The Stringlist is the list of 'input strings' - * associatied with the AVL nodes Stringelem. - */ -typedef struct stringlist { - const char *sl_string; - struct stringlist *sl_next; -} Stringlist; - -/* - * Nodes for the initial AVL tree which contains all of - * the input strings. The AVL tree is indexed off of - * the length of the strings. This permits later traversal - * of all of the strings based off of their string length. - */ -typedef struct { - avl_node_t se_avlnode; - Stringlist *se_strlist; - uint_t se_stlen; -} Stringelem; - - -/* - * Pointer to the Master string, other strings may be suffixes - * of this string. - */ -struct str_master { - const char *sm_str; /* pointer to master string */ - Str_master *sm_next; /* used for tracking master strings */ - uint_t sm_stlen; /* length of master string */ - uint_t sm_hashval; /* hashval of master string */ - uint_t sm_stoff; /* offset into destination strtab */ -}; - - -/* - * Represents a individual string that was input into - * the String hash table. The string may either be a - * suffix of another string or a master string. - */ -struct str_hash { - uint_t hi_stlen; /* string length */ - uint_t hi_refcnt; /* # of references to str */ - uint_t hi_hashval; /* hash for string */ - Str_master *hi_mstr; /* pointer to master string */ - Str_hash *hi_next; /* next entry in hash bckt */ -}; - -/* - * Controlling data structure for a String Table - */ -struct str_tbl { - avl_tree_t *st_strtree; /* avl tree of initial strs */ - char *st_strbuf; /* string buffer */ - Str_hash **st_hashbcks; /* hash buckets */ - Str_master *st_mstrlist; /* list of all master strings */ - uint_t st_fullstringsize; /* uncompressed table size */ - uint_t st_nextoff; /* next available string */ - uint_t st_stringsize; /* compressed size */ - uint_t st_stringcnt; /* # of strings */ - uint_t st_hbckcnt; /* # of buckets in hashlist */ - uint_t st_flags; -}; - -#define FLG_STTAB_COOKED 0x00000001 /* offset has been assigned */ -#define FLG_STTAB_COMPRESS 0x00000002 /* build compressed str tab */ - -/* - * starting value for use with string hashing functions - * inside of string_table.c - */ -#define HASHSEED 5381 - /* - * Flags for st_new + * Exported, opaque string table handle. */ -#define FLG_STNEW_COMPRESS 0x00000001 /* build compressed str tab */ +typedef struct str_tbl Str_tbl; /* - * exported string_table.c functions + * Exported string table functions. */ extern int st_delstring(Str_tbl *, const char *); extern void st_destroy(Str_tbl *); extern uint_t st_getstrtab_sz(Str_tbl *); extern const char *st_getstrbuf(Str_tbl *); extern int st_insert(Str_tbl *, const char *); +extern Str_tbl *st_new(uint_t); extern int st_setstrbuf(Str_tbl *, char *, uint_t); extern int st_setstring(Str_tbl *, const char *, uint_t *); -extern Str_tbl *st_new(uint_t); + +/* + * Exported flags values for st_new(). + */ +#define FLG_STNEW_COMPRESS 0x01 /* compressed string table */ #ifdef __cplusplus } diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c index ff0226c683..9d90bad446 100644 --- a/usr/src/cmd/sgs/libld/common/sections.c +++ b/usr/src/cmd/sgs/libld/common/sections.c @@ -39,7 +39,7 @@ #include "msg.h" #include "_libld.h" -static void +inline static void remove_local(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) { Sym *sym = sdp->sd_sym; @@ -49,11 +49,13 @@ remove_local(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) if ((ofl->ofl_flags1 & FLG_OF1_REDLSYM) == 0) { ofl->ofl_locscnt--; + err = st_delstring(ofl->ofl_strtab, sdp->sd_name); assert(err != -1); if (allow_ldynsym && ldynsym_symtype[type]) { ofl->ofl_dynlocscnt--; + err = st_delstring(ofl->ofl_dynstrtab, sdp->sd_name); assert(err != -1); /* Remove from sort section? */ @@ -63,7 +65,7 @@ remove_local(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) sdp->sd_flags |= FLG_SY_ISDISC; } -static void +inline static void remove_scoped(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) { Sym *sym = sdp->sd_sym; @@ -79,6 +81,7 @@ remove_scoped(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) if (allow_ldynsym && ldynsym_symtype[type]) { ofl->ofl_dynscopecnt--; + err = st_delstring(ofl->ofl_dynstrtab, sdp->sd_name); assert(err != -1); /* Remove from sort section? */ @@ -87,11 +90,80 @@ remove_scoped(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym) sdp->sd_flags1 |= FLG_SY1_ELIM; } -#pragma inline(remove_local) -#pragma inline(remove_scoped) +inline static void +ignore_sym(Ofl_desc *ofl, Ifl_desc *ifl, Sym_desc *sdp, int allow_ldynsym) +{ + Os_desc *osp; + Is_desc *isp = sdp->sd_isc; + uchar_t bind = ELF_ST_BIND(sdp->sd_sym->st_info); + + if (bind == STB_LOCAL) { + uchar_t type = ELF_ST_TYPE(sdp->sd_sym->st_info); + + /* + * Skip section symbols, these were never collected in the + * first place. + */ + if (type == STT_SECTION) + return; + + /* + * Determine if the whole file is being removed. Remove any + * file symbol, and any symbol that is not associated with a + * section, provided the symbol has not been identified as + * (update) required. + */ + if (((ifl->ifl_flags & FLG_IF_FILEREF) == 0) && + ((type == STT_FILE) || ((isp == NULL) && + ((sdp->sd_flags & FLG_SY_UPREQD) == 0)))) { + DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp)); + if (ifl->ifl_flags & FLG_IF_IGNORE) + remove_local(ofl, sdp, allow_ldynsym); + return; + } + + } else { + /* + * Global symbols can only be eliminated when the interfaces of + * an object have been defined via versioning/scoping. + */ + if ((sdp->sd_flags1 & FLG_SY1_HIDDEN) == 0) + return; + + /* + * Remove any unreferenced symbols that are not associated with + * a section. + */ + if ((isp == NULL) && ((sdp->sd_flags & FLG_SY_UPREQD) == 0)) { + DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp)); + if (ifl->ifl_flags & FLG_IF_IGNORE) + remove_scoped(ofl, sdp, allow_ldynsym); + return; + } + } + + /* + * Do not discard any symbols that are associated with non-allocable + * segments. + */ + if (isp && ((isp->is_flags & FLG_IS_SECTREF) == 0) && + ((osp = isp->is_osdesc) != 0) && + (osp->os_sgdesc->sg_phdr.p_type == PT_LOAD)) { + DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp)); + if (ifl->ifl_flags & FLG_IF_IGNORE) { + if (bind == STB_LOCAL) + remove_local(ofl, sdp, allow_ldynsym); + else + remove_scoped(ofl, sdp, allow_ldynsym); + } + } +} /* - * If -zignore is in effect, scan all input sections to see if there are any + * If -zignore has been in effect, scan all input files to determine if the + * file, or sections from the file, have been referenced. If not, the file or + * some of the files sections can be discarded. + * * which haven't been referenced (and hence can be discarded). If sections are * to be discarded, rescan the output relocations and the symbol table and * remove the relocations and symbol entries that are no longer required. @@ -112,9 +184,7 @@ ignore_section_processing(Ofl_desc *ofl) Listnode *lnp; Ifl_desc *ifl; Rel_cache *rcp; - int allow_ldynsym; - - allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl); + int allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl); for (LIST_TRAVERSE(&ofl->ofl_objs, lnp, ifl)) { uint_t num, discard; @@ -165,82 +235,28 @@ ignore_section_processing(Ofl_desc *ofl) */ for (num = 1; num < ifl->ifl_symscnt; num++) { Sym_desc *sdp; - Sym *symp; - Os_desc *osp; - /* LINTED - only used for assert() */ - int err; - uchar_t type; - - sdp = ifl->ifl_oldndx[num]; - symp = sdp->sd_sym; - type = ELF_ST_TYPE(symp->st_info); /* - * If the whole file is being eliminated, remove the - * local file symbol, and any COMMON symbols (which - * aren't associated with a section) provided they - * haven't been referenced by a relocation. + * If the symbol definition has been resolved to another + * file, or the symbol has already been discarded or + * eliminated, skip it. */ - if ((ofl->ofl_flags1 & FLG_OF1_IGNORE) && - ((ifl->ifl_flags & FLG_IF_FILEREF) == 0) && - ((type == STT_FILE) || - ((symp->st_shndx == SHN_COMMON) && - ((sdp->sd_flags & FLG_SY_UPREQD) == 0)))) { - remove_local(ofl, sdp, allow_ldynsym); - continue; - } - - /* - * Skip any undefined, reserved section symbols, already - * discarded or eliminated symbols. Also skip any - * symbols that don't originate from a section, or - * aren't defined from the file being examined. - */ - if ((symp->st_shndx == SHN_UNDEF) || - (symp->st_shndx >= SHN_LORESERVE) || - (type == STT_SECTION) || + sdp = ifl->ifl_oldndx[num]; + if ((sdp->sd_file != ifl) || (sdp->sd_flags & FLG_SY_ISDISC) || - (sdp->sd_flags1 & FLG_SY1_ELIM) || - (sdp->sd_isc == 0) || (sdp->sd_file != ifl)) + (sdp->sd_flags1 & FLG_SY1_ELIM)) continue; /* - * If any references were made against the section - * the symbol is being defined in - skip it. + * Complete the investigation of the symbol. */ - if ((sdp->sd_isc->is_flags & FLG_IS_SECTREF) || - ((ifl->ifl_flags & FLG_IF_FILEREF) && - ((osp = sdp->sd_isc->is_osdesc) != 0) && - (osp->os_sgdesc->sg_phdr.p_type != PT_LOAD))) - continue; - - /* - * Finish processing any local symbols. - */ - if (ELF_ST_BIND(symp->st_info) == STB_LOCAL) { - if (ofl->ofl_flags1 & FLG_OF1_IGNORE) - remove_local(ofl, sdp, allow_ldynsym); - - DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, - sdp, sdp->sd_isc)); - continue; - } - - /* - * Global symbols can only be eliminated when an objects - * interfaces (versioning/scoping) is defined. - */ - if (sdp->sd_flags1 & FLG_SY1_HIDDEN) { - if (ofl->ofl_flags1 & FLG_OF1_IGNORE) - remove_scoped(ofl, sdp, allow_ldynsym); - - DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, - sdp, sdp->sd_isc)); - continue; - } + ignore_sym(ofl, ifl, sdp, allow_ldynsym); } } + /* + * If we were only here to solicit debugging diagnostics, we're done. + */ if ((ofl->ofl_flags1 & FLG_OF1_IGNPRC) == 0) return (1); @@ -249,45 +265,44 @@ ignore_section_processing(Ofl_desc *ofl) * ignored sections. If one is found, decrement the total outrel count. */ for (LIST_TRAVERSE(&ofl->ofl_outrels, lnp, rcp)) { - Rel_desc *orsp; - Os_desc *relosp; + Rel_desc *rsp; + Os_desc *osp; /* LINTED */ - for (orsp = (Rel_desc *)(rcp + 1); - orsp < rcp->rc_free; orsp++) { - Is_desc *_isdesc = orsp->rel_isdesc; + for (rsp = (Rel_desc *)(rcp + 1); rsp < rcp->rc_free; rsp++) { + Is_desc *isc = rsp->rel_isdesc; uint_t flags, entsize; Shdr *shdr; Ifl_desc *ifl; - if ((_isdesc == 0) || - ((_isdesc->is_flags & (FLG_IS_SECTREF))) || - ((ifl = _isdesc->is_file) == 0) || + if ((isc == 0) || + ((isc->is_flags & (FLG_IS_SECTREF))) || + ((ifl = isc->is_file) == 0) || ((ifl->ifl_flags & FLG_IF_IGNORE) == 0) || - ((shdr = _isdesc->is_shdr) == 0) || + ((shdr = isc->is_shdr) == 0) || ((shdr->sh_flags & SHF_ALLOC) == 0)) continue; - flags = orsp->rel_flags; + flags = rsp->rel_flags; if (flags & (FLG_REL_GOT | FLG_REL_BSS | FLG_REL_NOINFO | FLG_REL_PLT)) continue; - relosp = orsp->rel_osdesc; + osp = rsp->rel_osdesc; - if (orsp->rel_flags & FLG_REL_RELA) + if (rsp->rel_flags & FLG_REL_RELA) entsize = sizeof (Rela); else entsize = sizeof (Rel); - assert(relosp->os_szoutrels > 0); - relosp->os_szoutrels -= entsize; + assert(osp->os_szoutrels > 0); + osp->os_szoutrels -= entsize; if (!(flags & FLG_REL_PLT)) ofl->ofl_reloccntsub++; - if (orsp->rel_rtype == M_R_RELATIVE) + if (rsp->rel_rtype == M_R_RELATIVE) ofl->ofl_relocrelcnt--; } } diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c index 5052d81511..8ff5489872 100644 --- a/usr/src/cmd/sgs/libld/common/syms.c +++ b/usr/src/cmd/sgs/libld/common/syms.c @@ -73,7 +73,7 @@ ld_sym_avl_comp(const void *elem1, const void *elem2) /* * Focal point for verifying symbol names. */ -static const char * +inline static const char * string(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, size_t strsize, int symndx, Word shndx, const char *symsecname, const char *strsecname, Word *flags) @@ -231,7 +231,7 @@ ld_sym_find(const char *name, Word hash, avl_index_t *where, Ofl_desc *ofl) /* * Perform search for symbol in AVL tree. Note that the 'where' field * is passed in from the caller. If a 'where' is present, it can be - * used in subsequent 'sym_enter()' calls if required. + * used in subsequent 'ld_sym_enter()' calls if required. */ sav = avl_find(&ofl->ofl_symavl, &qsav, where); @@ -1957,8 +1957,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) if (sdp->sd_isc && (sdp->sd_isc->is_flags & FLG_IS_DISCARD)) { sdp->sd_flags |= FLG_SY_ISDISC; - DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, - sdp, sdp->sd_isc)); + DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp)); continue; } @@ -2183,8 +2182,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) sdp->sd_flags = FLG_SY_ISDISC; ifl->ifl_oldndx[ndx] = sdp; - DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp, - sdp->sd_isc)); + DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp)); continue; } } diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c index 858f5c9289..503415692e 100644 --- a/usr/src/cmd/sgs/libld/common/update.c +++ b/usr/src/cmd/sgs/libld/common/update.c @@ -1927,7 +1927,8 @@ update_osym(Ofl_desc *ofl) dynsort_compare_syms = ldynsym; qsort(dynsymsort, dynsymsort_ndx, sizeof (*dynsymsort), dynsort_compare); - dynsort_dupwarn(ofl, ldynsym, dynstr->st_strbuf, + dynsort_dupwarn(ofl, ldynsym, + st_getstrbuf(dynstr), dynsymsort, dynsymsort_ndx, MSG_ORIG(MSG_SCN_DYNSYMSORT)); } @@ -1941,7 +1942,8 @@ update_osym(Ofl_desc *ofl) dynsort_compare_syms = ldynsym; qsort(dyntlssort, dyntlssort_ndx, sizeof (*dyntlssort), dynsort_compare); - dynsort_dupwarn(ofl, ldynsym, dynstr->st_strbuf, + dynsort_dupwarn(ofl, ldynsym, + st_getstrbuf(dynstr), dyntlssort, dyntlssort_ndx, MSG_ORIG(MSG_SCN_DYNTLSSORT)); } diff --git a/usr/src/cmd/sgs/liblddbg/common/cap.c b/usr/src/cmd/sgs/liblddbg/common/cap.c index 6659c302cc..43f15883d5 100644 --- a/usr/src/cmd/sgs/liblddbg/common/cap.c +++ b/usr/src/cmd/sgs/liblddbg/common/cap.c @@ -25,6 +25,7 @@ */ #pragma ident "%Z%%M% %I% %E% SMI" +#include <stdio.h> #include <debug.h> #include <libld.h> #include <conv.h> diff --git a/usr/src/cmd/sgs/liblddbg/common/got.c b/usr/src/cmd/sgs/liblddbg/common/got.c index 7494a7a19c..17fe407110 100644 --- a/usr/src/cmd/sgs/liblddbg/common/got.c +++ b/usr/src/cmd/sgs/liblddbg/common/got.c @@ -25,7 +25,7 @@ */ #pragma ident "%Z%%M% %I% %E% SMI" -#include <stdlib.h> +#include <stdio.h> #include "_debug.h" #include "msg.h" #include "libld.h" diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg index 1f19a9e207..b5b412568c 100644 --- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg @@ -566,12 +566,11 @@ discarded: member of existing group: %s:%s" @ MSG_SEC_STRTAB_STND "strtab=%s; full size: %d; uncompressed" -@ MSG_SEC_STRTAB_COMP "strtab=%s; full size: %d -> compressed down to: %d" -@ MSG_SEC_STRTAB_HD "Compressed String Table: %s \ - [%d buckets]:" -@ MSG_SEC_STRTAB_BCKT " Bucket[%3d]:" -@ MSG_SEC_STRTAB_MSTR " ref[%2d] %s <master>" -@ MSG_SEC_STRTAB_SUFSTR " ref[%2d] %s <suffix of> %s" +@ MSG_SEC_STRTAB_COMP "strtab=%s; full size: %d; compressed down to: %d" +@ MSG_SEC_STRTAB_HD "strtab=%s; compression information [%d buckets]:" +@ MSG_SEC_STRTAB_BCKT " bucket[%d]:" +@ MSG_SEC_STRTAB_MSTR " [%d] %s <master>" +@ MSG_SEC_STRTAB_SUFSTR " [%d] %s <suffix of: %s>" # Unused messages @@ -638,8 +637,10 @@ @ MSG_SYM_ELIMINATING "symbol=%s; eliminating" @ MSG_SYM_NOTELIMINATE "symbol=%s; not eliminated: referenced by \ section=%s, entry[%d]" -@ MSG_SYM_DISCARDED "symbol=%s; discarded because it is part of \ +@ MSG_SYM_DISCARD_SEC "symbol=%s; discarded: originates from unused or \ discarded section=%s from file=%s" +@ MSG_SYM_DISCARD_FILE "symbol=%s; discarded: originates from unused or \ + discarded file=%s" @ MSG_SYM_AOUT "symbol=%s; (original AOUT name)" @ MSG_SYM_LOOKUP "symbol=%s; lookup in file=%s [ %s ]" diff --git a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg index 73122cd337..fbabd9b205 100644 --- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg +++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg @@ -342,8 +342,8 @@ void Dbg32_syms_ar_title(Lm_list *, const char *, int); void Dbg64_syms_ar_title(Lm_list *, const char *, int); void Dbg32_syms_created(Lm_list *, const char *); void Dbg64_syms_created(Lm_list *, const char *); -void Dbg32_syms_discarded(Lm_list *, Sym_desc *, Is_desc *); -void Dbg64_syms_discarded(Lm_list *, Sym_desc *, Is_desc *); +void Dbg32_syms_discarded(Lm_list *, Sym_desc *); +void Dbg64_syms_discarded(Lm_list *, Sym_desc *); void Dbg32_syms_dlsym(Rt_map *, const char *, const char *, int); void Dbg64_syms_dlsym(Rt_map *, const char *, const char *, int); void Dbg32_syms_entered(Ofl_desc *, Sym *, Sym_desc *); diff --git a/usr/src/cmd/sgs/liblddbg/common/sections.c b/usr/src/cmd/sgs/liblddbg/common/sections.c index a88653f084..bd1b76e2de 100644 --- a/usr/src/cmd/sgs/liblddbg/common/sections.c +++ b/usr/src/cmd/sgs/liblddbg/common/sections.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -28,23 +28,12 @@ #include "msg.h" #include "_debug.h" #include "libld.h" - -/* - * Error message string table. - */ -static const Msg order_errors[] = { - MSG_ORD_ERR_INFORANGE, /* MSG_INTL(MSG_ORD_ERR_INFORANGE) */ - MSG_ORD_ERR_ORDER, /* MSG_INTL(MSG_ORD_ERR_ORDER) */ - MSG_ORD_ERR_LINKRANGE, /* MSG_INTL(MSG_ORD_ERR_LINKRANGE) */ - MSG_ORD_ERR_FLAGS, /* MSG_INTL(MSG_ORD_ERR_FLAGS) */ - MSG_ORD_ERR_CYCLIC, /* MSG_INTL(MSG_ORD_ERR_CYCLIC) */ - MSG_ORD_ERR_LINKINV /* MSG_INTL(MSG_ORD_ERR_LINKINV) */ -}; +#include "_string_table.h" void Dbg_sec_strtab(Lm_list *lml, Os_desc *osp, Str_tbl *stp) { - uint_t i; + uint_t cnt; if (DBG_NOTCLASS(DBG_C_STRTAB)) return; @@ -55,10 +44,10 @@ Dbg_sec_strtab(Lm_list *lml, Os_desc *osp, Str_tbl *stp) Dbg_util_nl(lml, DBG_NL_STD); if (stp->st_flags & FLG_STTAB_COMPRESS) dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_COMP), osp->os_name, - stp->st_fullstringsize, stp->st_stringsize); + stp->st_fullstrsize, stp->st_strsize); else dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_STND), osp->os_name, - stp->st_fullstringsize); + stp->st_fullstrsize); if ((DBG_NOTDETAIL()) || ((stp->st_flags & FLG_STTAB_COMPRESS) == 0)) @@ -68,27 +57,31 @@ Dbg_sec_strtab(Lm_list *lml, Os_desc *osp, Str_tbl *stp) dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_HD), osp->os_name, stp->st_hbckcnt); - for (i = 0; i < stp->st_hbckcnt; i++) { - Str_hash *sthash; + for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) { + Str_hash *strhash = stp->st_hashbcks[cnt]; + + if (strhash == 0) + continue; - dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_BCKT), i); + dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_BCKT), cnt); - for (sthash = stp->st_hashbcks[i]; sthash; - sthash = sthash->hi_next) { - uint_t stroff = sthash->hi_mstr->sm_stlen - - sthash->hi_stlen; + while (strhash) { + uint_t stroff = strhash->hi_mstr->sm_strlen - + strhash->hi_strlen; if (stroff == 0) { dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_MSTR), - sthash->hi_refcnt, sthash->hi_mstr->sm_str); + strhash->hi_refcnt, + strhash->hi_mstr->sm_str); } else { dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_SUFSTR), - sthash->hi_refcnt, - &sthash->hi_mstr->sm_str[stroff], - sthash->hi_mstr->sm_str); + strhash->hi_refcnt, + &strhash->hi_mstr->sm_str[stroff], + strhash->hi_mstr->sm_str); } - } + strhash = strhash->hi_next; + } } } @@ -143,7 +136,7 @@ Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp) void Dbg_sec_discarded(Lm_list *lml, Is_desc *isp, Is_desc *disp) { - if (DBG_NOTCLASS(DBG_C_SECTIONS)) + if (DBG_NOTCLASS(DBG_C_SECTIONS | DBG_C_UNUSED)) return; dbg_print(lml, MSG_INTL(MSG_SEC_DISCARDED), isp->is_basename, @@ -244,6 +237,18 @@ Dbg_sec_order_list(Ofl_desc *ofl, int flag) Dbg_util_nl(lml, DBG_NL_STD); } +/* + * Error message string table. + */ +static const Msg order_errors[] = { + MSG_ORD_ERR_INFORANGE, /* MSG_INTL(MSG_ORD_ERR_INFORANGE) */ + MSG_ORD_ERR_ORDER, /* MSG_INTL(MSG_ORD_ERR_ORDER) */ + MSG_ORD_ERR_LINKRANGE, /* MSG_INTL(MSG_ORD_ERR_LINKRANGE) */ + MSG_ORD_ERR_FLAGS, /* MSG_INTL(MSG_ORD_ERR_FLAGS) */ + MSG_ORD_ERR_CYCLIC, /* MSG_INTL(MSG_ORD_ERR_CYCLIC) */ + MSG_ORD_ERR_LINKINV /* MSG_INTL(MSG_ORD_ERR_LINKINV) */ +}; + void Dbg_sec_order_error(Lm_list *lml, Ifl_desc *ifl, Word ndx, int error) { diff --git a/usr/src/cmd/sgs/liblddbg/common/syminfo.c b/usr/src/cmd/sgs/liblddbg/common/syminfo.c index f33b78066d..36aeecfe66 100644 --- a/usr/src/cmd/sgs/liblddbg/common/syminfo.c +++ b/usr/src/cmd/sgs/liblddbg/common/syminfo.c @@ -26,6 +26,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sgs.h> +#include <stdio.h> #include <debug.h> #include <msg.h> diff --git a/usr/src/cmd/sgs/liblddbg/common/syms.c b/usr/src/cmd/sgs/liblddbg/common/syms.c index fd81e514a2..03f302040a 100644 --- a/usr/src/cmd/sgs/liblddbg/common/syms.c +++ b/usr/src/cmd/sgs/liblddbg/common/syms.c @@ -178,20 +178,28 @@ Dbg_syms_spec_title(Lm_list *lml) } void -Dbg_syms_discarded(Lm_list *lml, Sym_desc *sdp, Is_desc *disp) +Dbg_syms_discarded(Lm_list *lml, Sym_desc *sdp) { - const char *sectname; + const char *file; - if (DBG_NOTCLASS(DBG_C_SYMBOLS)) + if (DBG_NOTCLASS(DBG_C_SYMBOLS | DBG_C_UNUSED)) return; if (DBG_NOTDETAIL()) return; - if ((sectname = disp->is_basename) == 0) - sectname = disp->is_name; + if ((sdp->sd_file == NULL) || ((file = sdp->sd_file->ifl_name) == NULL)) + file = MSG_INTL(MSG_STR_UNKNOWN); + + if (sdp->sd_isc) { + const char *sec; - dbg_print(lml, MSG_INTL(MSG_SYM_DISCARDED), - Dbg_demangle_name(sdp->sd_name), sectname, disp->is_file->ifl_name); + if ((sec = sdp->sd_isc->is_basename) == 0) + sec = sdp->sd_isc->is_name; + dbg_print(lml, MSG_INTL(MSG_SYM_DISCARD_SEC), + Dbg_demangle_name(sdp->sd_name), sec, file); + } else + dbg_print(lml, MSG_INTL(MSG_SYM_DISCARD_FILE), + Dbg_demangle_name(sdp->sd_name), file); } void diff --git a/usr/src/cmd/sgs/liblddbg/common/version.c b/usr/src/cmd/sgs/liblddbg/common/version.c index 12fa399e76..914d5d11ec 100644 --- a/usr/src/cmd/sgs/liblddbg/common/version.c +++ b/usr/src/cmd/sgs/liblddbg/common/version.c @@ -25,7 +25,7 @@ */ #pragma ident "%Z%%M% %I% %E% SMI" -#include <link.h> +#include <stdio.h> #include <debug.h> #include "msg.h" #include "_debug.h" diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README index a1c186c220..0438300045 100644 --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README @@ -1300,3 +1300,4 @@ Bugid Risk Synopsis PSARC/2007/620 elfdump -T, and simplified matching 6627765 soffice failure after integration of 6603313 - dangling GROUP pointer. 6319025 SUNWbtool packaging issues in Nevada and S10u1. +6629404 ld with -z ignore doesn't scale diff --git a/usr/src/cmd/sgs/rtld/common/dlfcns.c b/usr/src/cmd/sgs/rtld/common/dlfcns.c index d4e54beca3..61038dbfed 100644 --- a/usr/src/cmd/sgs/rtld/common/dlfcns.c +++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c @@ -35,6 +35,7 @@ #include "_synonyms.h" #include <sys/debug.h> +#include <stdio.h> #include <string.h> #include <dlfcn.h> #include <synch.h> diff --git a/usr/src/cmd/sgs/tools/common/sgsmsg.c b/usr/src/cmd/sgs/tools/common/sgsmsg.c index f2757508b4..3b06e5ff6a 100644 --- a/usr/src/cmd/sgs/tools/common/sgsmsg.c +++ b/usr/src/cmd/sgs/tools/common/sgsmsg.c @@ -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,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * sgsmsg generates several message files from an input template file. Messages * are constructed for use with gettext(3i) - the default - or catgets(3c). The @@ -80,7 +79,7 @@ #include <sys/param.h> #include <sgs.h> -#include <string_table.h> +#include <_string_table.h> /* * Define any error message strings. @@ -150,14 +149,13 @@ message_append(const char *defn, const char *message) (void) fprintf(stderr, Errmsg_nmem, strerror(errno)); exit(1); } - if (stp == 0) { - /* - * Initialize string table - */ - if ((stp = st_new(FLG_STNEW_COMPRESS)) == 0) { - (void) fprintf(stderr, Errmsg_stnw, strerror(errno)); - exit(1); - } + + /* + * Initialize the string table. + */ + if ((stp == 0) && ((stp = st_new(FLG_STNEW_COMPRESS)) == NULL)) { + (void) fprintf(stderr, Errmsg_stnw, strerror(errno)); + exit(1); } @@ -313,45 +311,51 @@ getmesgid(char *id) return (0); } - /* * Dump contents of String Table to standard out */ static void dump_stringtab(Str_tbl *stp) { - uint_t i; + uint_t cnt; if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) { - (void) printf("uncompressed strings: %d\n", - stp->st_fullstringsize); + (void) printf("string table full size: %d: uncompressed\n", + stp->st_fullstrsize); return; } + (void) printf("string table full size: %d compressed down to: %d\n\n", + stp->st_fullstrsize, stp->st_strsize); + (void) printf("string table compression information [%d buckets]:\n", + stp->st_hbckcnt); + + for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) { + Str_hash *sthash = stp->st_hashbcks[cnt]; + + if (sthash == 0) + continue; + + (void) printf(" bucket: [%d]\n", cnt); + + while (sthash) { + uint_t stroff = sthash->hi_mstr->sm_strlen - + sthash->hi_strlen; - for (i = 0; i < stp->st_hbckcnt; i++) { - Str_hash *sthash; - (void) printf("Bucket: [%3d]\n", i); - for (sthash = stp->st_hashbcks[i]; sthash; - sthash = sthash->hi_next) { - uint_t stroff; - stroff = sthash->hi_mstr->sm_stlen - sthash->hi_stlen; if (stroff == 0) { - (void) printf(" %2d %s <master>\n", - sthash->hi_refcnt, - sthash->hi_mstr->sm_str); + (void) printf(" [%d]: '%s' <master>\n", + sthash->hi_refcnt, sthash->hi_mstr->sm_str); } else { - const char *str; - str = &sthash->hi_mstr->sm_str[stroff]; - (void) printf(" %2d %s <suffix of> -> %s\n", - sthash->hi_refcnt, - str, sthash->hi_mstr->sm_str); + (void) printf(" [%d]: '%s' <suffix of: " + "'%s'>\n", sthash->hi_refcnt, + &sthash->hi_mstr->sm_str[stroff], + sthash->hi_mstr->sm_str); } + sthash = sthash->hi_next; } } - (void) printf("fullstringsize: %d compressed: %d\n", - stp->st_fullstringsize, stp->st_stringsize); } + /* * Initialize the message definition header file stream. */ @@ -519,7 +523,6 @@ fini_defs(void) return (0); } - /* * The entire messaging file has been scanned - and all strings have been * inserted into the string_table. We can now walk the message queue @@ -899,6 +902,7 @@ message: * unless an escape character is found * terminate the data string with a 0. */ + /* BEGIN CSTYLED */ if (*token == '"') { if (fdlint && (fprintf(fdlint, "%c", *token) < 0)) { @@ -924,6 +928,7 @@ message: _token = '\0'; } else _token = *token; + /* END CSTYLED */ } if (fdmsgs && (prtmsgs == 1) && @@ -1186,7 +1191,6 @@ main(int argc, char ** argv) if (vflag) dump_stringtab(stp); - /* * Close up everything and go home. */ diff --git a/usr/src/cmd/sgs/tools/common/string_table.c b/usr/src/cmd/sgs/tools/common/string_table.c index c8d0aacc63..b3b669a8c3 100644 --- a/usr/src/cmd/sgs/tools/common/string_table.c +++ b/usr/src/cmd/sgs/tools/common/string_table.c @@ -20,46 +20,42 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" -#include <string_table.h> +#include <_string_table.h> #include <strings.h> #include <sgs.h> #include <stdio.h> - - /* - * This file provides the interfaces to build a Str_tbl suitable - * for use by either the sgsmsg system or a standard ELF - * SHT_STRTAB. + * This file provides the interfaces to build a Str_tbl suitable for use by + * either the sgsmsg message system, or a standard ELF string table (SHT_STRTAB) + * as created by ld(1). * - * There are two modes which can be used when constructing a - * string table: + * There are two modes which can be used when constructing a string table: * * st_new(0) * standard string table - no compression. This is the - * traditional method and fast + * traditional, fast method. * - * st_new(FLG_STNEW_COMPRESS) - * build a compressed string table which both - * eliminates duplicate strings and permits - * strings with common suffixes (atexit vs. exit) to - * overlap in the table. This provides space - * savings for many string tables. + * st_new(FLG_STTAB_COMPRESS) + * builds a compressed string table which both eliminates + * duplicate strings, and permits strings with common suffixes + * (atexit vs. exit) to overlap in the table. This provides space + * savings for many string tables. Although more work than the + * traditional method, the algorithms used are designed to scale + * and keep any overhead at a minimum. * - * These string tables are now built with a common interface in a - * two-pass manner, the first pass it to find all of the strings - * required for the string-table and to calculate the size that - * will be required for the final string table. + * These string tables are built with a common interface in a two-pass manner. + * The first pass finds all of the strings required for the string-table and + * calculates the size required for the final string table. * - * The second pass allocates the string table and populates the - * strings into the table and returns the offsets the strings - * have been assigned. + * The second pass allocates the string table, populates the strings into the + * table and returns the offsets the strings have been assigned. * * The calling sequence to build and populate a string table is: * @@ -71,7 +67,6 @@ * * st_delstring(st?); // remove string previously * // inserted - * * st_insert(stN); * * st_getstrtab_sz(); // freezes strtab and computes @@ -113,219 +108,234 @@ * The above method will find all suffixes of a given string given * that the strings are inserted from shortest to longest. That is * why this is a two phase method, we first collect all of the - * strings and store them based off of their length in a nice AVL tree. + * strings and store them based off of their length in an AVL tree. * Once all of the strings have been submitted we then start the * hash table build by traversing the AVL tree in order and * inserting the strings from shortest to longest as described * above. - * */ /* LINTLIBRARY */ - -int -strlen_compare(const void *elem1, const void *elem2) +static int +avl_len_compare(const void *n1, const void *n2) { - uint_t l1, l2; - l1 = ((Stringelem *)elem1)->se_stlen; - l2 = ((Stringelem *)elem2)->se_stlen; + uint_t len1, len2; + + len1 = ((LenNode *)n1)->ln_strlen; + len2 = ((LenNode *)n2)->ln_strlen; - if (l1 == l2) + if (len1 == len2) return (0); - if (l2 < l1) + if (len2 < len1) return (1); - return (-1); } +static int +avl_str_compare(const void *n1, const void *n2) +{ + const char *str1, *str2; + int rc; + + str1 = ((StrNode *)n1)->sn_str; + str2 = ((StrNode *)n2)->sn_str; + + rc = strcmp(str1, str2); + if (rc > 0) + return (1); + if (rc < 0) + return (-1); + return (0); +} + /* - * Return a initialized Str_tbl - returns NULL on failure. - * - * stflags: - * - * FLG_STNEW_COMPRESS - build a compressed string table + * Return an initialized Str_tbl - returns NULL on failure. * + * flags: + * FLG_STTAB_COMPRESS - build a compressed string table */ Str_tbl * -st_new(uint_t stflags) +st_new(uint_t flags) { Str_tbl *stp; - if ((stp = calloc(sizeof (Str_tbl), 1)) == 0) - return (0); + if ((stp = calloc(sizeof (Str_tbl), 1)) == NULL) + return (NULL); /* * Start with a leading '\0' - it's tradition. */ - stp->st_stringsize = stp->st_fullstringsize = stp->st_nextoff = 1; + stp->st_strsize = stp->st_fullstrsize = stp->st_nextoff = 1; /* - * Do we compress this string table + * Do we compress this string table? */ - if ((stflags & FLG_STNEW_COMPRESS) == 0) + stp->st_flags = flags; + if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) return (stp); - stp->st_flags |= FLG_STTAB_COMPRESS; - if ((stp->st_strtree = calloc(sizeof (avl_tree_t), 1)) == 0) { - return (0); - } + if ((stp->st_lentree = calloc(sizeof (avl_tree_t), 1)) == NULL) + return (NULL); - avl_create(stp->st_strtree, &strlen_compare, sizeof (Stringelem), - SGSOFFSETOF(Stringelem, se_avlnode)); + avl_create(stp->st_lentree, &avl_len_compare, sizeof (LenNode), + SGSOFFSETOF(LenNode, ln_avlnode)); return (stp); } /* - * Tear down a String_Table structure. - */ -void -st_destroy(Str_tbl *stp) -{ - Str_hash *sthash, *psthash; - Str_master *mstr, *pmstr; - uint_t i; - - /* - * cleanup the master strings - */ - for (mstr = stp->st_mstrlist, pmstr = 0; mstr; - mstr = mstr->sm_next) { - if (pmstr) - free(pmstr); - pmstr = mstr; - } - if (pmstr) - free(pmstr); - - if (stp->st_hashbcks) { - for (i = 0; i < stp->st_hbckcnt; i++) { - for (sthash = stp->st_hashbcks[i], psthash = 0; - sthash; sthash = sthash->hi_next) { - if (psthash) - free(psthash); - psthash = sthash; - } - if (psthash) - free(psthash); - } - free(stp->st_hashbcks); - } - free(stp); -} - - - - -/* - * Remove a previously inserted string from the Str_tbl + * Insert a new string into the Str_tbl. There are two AVL trees used. + * + * . The first LenNode AVL tree maintains a tree of nodes based on string + * sizes. + * . Each LenNode maintains a StrNode AVL tree for each string. Large + * applications have been known to contribute thousands of strings of + * the same size. Should strings need to be removed (-z ignore), then + * the string AVL tree makes this removal efficient and scalable. */ int -st_delstring(Str_tbl *stp, const char *str) +st_insert(Str_tbl *stp, const char *str) { - uint_t stlen; - Stringelem qstelem; - Stringelem *stelem; - Stringlist *stlist, *pstlist; + uint_t len; + StrNode *snp, sn = { 0 }; + LenNode *lnp, ln = { 0 }; + avl_index_t where; /* * String table can't have been cooked */ assert((stp->st_flags & FLG_STTAB_COOKED) == 0); - stlen = (uint_t)strlen(str); - stp->st_fullstringsize -= stlen + 1; + /* + * Null strings always point to the head of the string + * table - no reason to keep searching. + */ + if ((len = (uint_t)strlen(str)) == 0) + return (0); + + stp->st_fullstrsize += len + 1; + stp->st_strcnt++; if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) return (0); - qstelem.se_stlen = stlen; - if ((stelem = avl_find(stp->st_strtree, &qstelem, 0)) == NULL) { - /* - * no strings of this length recorded, let alone - * this specific string - someone goofed. - */ - return (-1); - } + /* + * From the controlling string table, determine which LenNode AVL node + * provides for this string length. If the node doesn't exist, insert + * a new node to represent this string length. + */ + ln.ln_strlen = len; + if ((lnp = avl_find(stp->st_lentree, &ln, &where)) == NULL) { + if ((lnp = calloc(sizeof (LenNode), 1)) == NULL) + return (-1); + lnp->ln_strlen = len; + avl_insert(stp->st_lentree, lnp, where); - pstlist = 0; - for (stlist = stelem->se_strlist; stlist; stlist = stlist->sl_next) { - if (strcmp(str, stlist->sl_string) == 0) - break; - pstlist = stlist; - } + if ((lnp->ln_strtree = calloc(sizeof (avl_tree_t), 1)) == NULL) + return (0); - if (stlist == 0) { - /* - * string was not found - */ - return (-1); + avl_create(lnp->ln_strtree, &avl_str_compare, sizeof (StrNode), + SGSOFFSETOF(StrNode, sn_avlnode)); } - if (pstlist == 0) { - /* - * String is first on list. - */ - stelem->se_strlist = stlist->sl_next; - } else { - /* - * remove string from list. - */ - pstlist->sl_next = stlist->sl_next; + /* + * From the string length AVL node determine whether a StrNode AVL node + * provides this string. If the node doesn't exist, insert a new node + * to represent this string. + */ + sn.sn_str = str; + if ((snp = avl_find(lnp->ln_strtree, &sn, &where)) == NULL) { + if ((snp = calloc(sizeof (StrNode), 1)) == NULL) + return (-1); + snp->sn_str = str; + avl_insert(lnp->ln_strtree, snp, where); } + snp->sn_refcnt++; - free(stlist); return (0); } - /* - * Insert a new string into the Str_tbl + * Remove a previously inserted string from the Str_tbl. */ int -st_insert(Str_tbl *stp, const char *str) +st_delstring(Str_tbl *stp, const char *str) { - uint_t stlen; - Stringelem qstelem; - Stringelem *stelem; - Stringlist *strlist; - avl_index_t where; + uint_t len; + LenNode *lnp, ln = { 0 }; + StrNode *snp, sn = { 0 }; /* * String table can't have been cooked */ assert((stp->st_flags & FLG_STTAB_COOKED) == 0); - stlen = (uint_t)strlen(str); - /* - * Null strings always point to the head of the string - * table - no reason to keep searching. - */ - if (stlen == 0) - return (0); - stp->st_fullstringsize += stlen + 1; - stp->st_stringcnt++; + len = (uint_t)strlen(str); + stp->st_fullstrsize -= len + 1; if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) return (0); - qstelem.se_stlen = strlen(str); - if ((stelem = avl_find(stp->st_strtree, &qstelem, - &where)) == NULL) { - if ((stelem = calloc(sizeof (Stringelem), 1)) == 0) - return (-1); - stelem->se_stlen = qstelem.se_stlen; - avl_insert(stp->st_strtree, stelem, where); + /* + * Determine which LenNode AVL node provides for this string length. + */ + ln.ln_strlen = len; + if ((lnp = avl_find(stp->st_lentree, &ln, 0)) != NULL) { + sn.sn_str = str; + if ((snp = avl_find(lnp->ln_strtree, &sn, 0)) != NULL) { + /* + * Reduce the reference count, and if zero remove the + * node. + */ + if (--snp->sn_refcnt == 0) + avl_remove(lnp->ln_strtree, snp); + return (0); + } } - if ((strlist = malloc(sizeof (Stringlist))) == 0) - return (-1); - strlist->sl_string = str; - strlist->sl_next = stelem->se_strlist; - stelem->se_strlist = strlist; + /* + * No strings of this length, or no string itself - someone goofed. + */ + return (-1); +} - return (0); +/* + * Tear down a String_Table structure. + */ +void +st_destroy(Str_tbl *stp) +{ + Str_hash *sthash, *psthash; + Str_master *mstr, *pmstr; + uint_t i; + + /* + * cleanup the master strings + */ + for (mstr = stp->st_mstrlist, pmstr = 0; mstr; + mstr = mstr->sm_next) { + if (pmstr) + free(pmstr); + pmstr = mstr; + } + if (pmstr) + free(pmstr); + + if (stp->st_hashbcks) { + for (i = 0; i < stp->st_hbckcnt; i++) { + for (sthash = stp->st_hashbcks[i], psthash = 0; + sthash; sthash = sthash->hi_next) { + if (psthash) + free(psthash); + psthash = sthash; + } + if (psthash) + free(psthash); + } + free(stp->st_hashbcks); + } + free(stp); } @@ -368,7 +378,7 @@ st_setstring(Str_tbl *stp, const char *str, uint_t *stoff) /* * Have we overflowed our assigned buffer? */ - if ((_stoff + stlen) > stp->st_fullstringsize) + if ((_stoff + stlen) > stp->st_fullstrsize) return (-1); memcpy(stp->st_strbuf + _stoff, str, stlen); *stoff = _stoff; @@ -377,26 +387,25 @@ st_setstring(Str_tbl *stp, const char *str, uint_t *stoff) } /* - * Calculate reverse hash for string + * Calculate reverse hash for string. */ hashval = HASHSEED; for (i = stlen; i >= 0; i--) { hashval = ((hashval << 5) + hashval) + - str[i]; /* h = ((h * 33) + c) */ + str[i]; /* h = ((h * 33) + c) */ } for (sthash = stp->st_hashbcks[hashval % stp->st_hbckcnt]; sthash; sthash = sthash->hi_next) { - if (sthash->hi_hashval == hashval) { - const char *hstr; + const char *hstr; - hstr = &sthash->hi_mstr->sm_str[ - sthash->hi_mstr->sm_stlen - - sthash->hi_stlen]; - if (strcmp(str, hstr) == 0) { - break; - } - } + if (sthash->hi_hashval != hashval) + continue; + + hstr = &sthash->hi_mstr->sm_str[sthash->hi_mstr->sm_strlen - + sthash->hi_strlen]; + if (strcmp(str, hstr) == 0) + break; } /* @@ -409,29 +418,33 @@ st_setstring(Str_tbl *stp, const char *str, uint_t *stoff) * Has this string been copied into the string table? */ mstr = sthash->hi_mstr; - if (mstr->sm_stoff == 0) { - uint_t mstlen = mstr->sm_stlen + 1; - mstr->sm_stoff = stp->st_nextoff; + if (mstr->sm_stroff == 0) { + uint_t mstrlen = mstr->sm_strlen + 1; + + mstr->sm_stroff = stp->st_nextoff; + /* * Have we overflowed our assigned buffer? */ - if ((mstr->sm_stoff + mstlen) > stp->st_fullstringsize) + if ((mstr->sm_stroff + mstrlen) > stp->st_fullstrsize) return (-1); - memcpy(stp->st_strbuf + mstr->sm_stoff, mstr->sm_str, - mstlen); - stp->st_nextoff += mstlen; + + (void) memcpy(stp->st_strbuf + mstr->sm_stroff, + mstr->sm_str, mstrlen); + stp->st_nextoff += mstrlen; } + /* - * Calculate offset of (sub)string + * Calculate offset of (sub)string. */ - *stoff = mstr->sm_stoff + mstr->sm_stlen - sthash->hi_stlen; + *stoff = mstr->sm_stroff + mstr->sm_strlen - sthash->hi_strlen; return (0); } static int -st_hash_insert(Str_tbl *stp, const char *str, uint_t stlen) +st_hash_insert(Str_tbl *stp, const char *str, uint_t len) { int i; uint_t hashval = HASHSEED; @@ -450,51 +463,48 @@ st_hash_insert(Str_tbl *stp, const char *str, uint_t stlen) * any suffixes already exist in the tree as we generate * the hash. */ - for (i = stlen; i >= 0; i--) { - + for (i = len; i >= 0; i--) { hashval = ((hashval << 5) + hashval) + - str[i]; /* h = ((h * 33) + c) */ + str[i]; /* h = ((h * 33) + c) */ + for (sthash = hashbcks[hashval % bckcnt]; sthash; sthash = sthash->hi_next) { - - if (sthash->hi_hashval == hashval) { - const char *hstr; - Str_master *_mstr; - - _mstr = sthash->hi_mstr; - hstr = &_mstr->sm_str[_mstr->sm_stlen - - sthash->hi_stlen]; - if (strcmp(&str[i], hstr) == 0) { - if (i == 0) { - /* - * Entry already in table, - * increment refcnt and get - * out. - */ - sthash->hi_refcnt++; - return (0); - } else { - /* - * If this 'suffix' is - * presently a 'master' string, - * then take over it's record. - */ - if (sthash->hi_stlen == - _mstr->sm_stlen) { - /* - * we should only do - * this once. - */ - assert(mstr == 0); - mstr = _mstr; - } - } + const char *hstr; + Str_master *_mstr; + + if (sthash->hi_hashval != hashval) + continue; + + _mstr = sthash->hi_mstr; + hstr = &_mstr->sm_str[_mstr->sm_strlen - + sthash->hi_strlen]; + + if (strcmp(&str[i], hstr)) + continue; + + if (i == 0) { + /* + * Entry already in table, increment refcnt and + * get out. + */ + sthash->hi_refcnt++; + return (0); + } else { + /* + * If this 'suffix' is presently a 'master + * string, then take over it's record. + */ + if (sthash->hi_strlen == _mstr->sm_strlen) { + /* + * we should only do this once. + */ + assert(mstr == 0); + mstr = _mstr; } } } } - /* * Do we need a new master string, or can we take over * one we already found in the table? @@ -507,23 +517,22 @@ st_hash_insert(Str_tbl *stp, const char *str, uint_t stlen) return (-1); mstr->sm_next = stp->st_mstrlist; stp->st_mstrlist = mstr; - stp->st_stringsize += stlen + 1; + stp->st_strsize += len + 1; } else { /* - * We are taking over a existing master string, - * the stringsize only increments by the - * difference between the currnet string and the - * previous master. + * We are taking over a existing master string, the string size + * only increments by the difference between the current string + * and the previous master. */ - assert(stlen > mstr->sm_stlen); - stp->st_stringsize += stlen - mstr->sm_stlen; + assert(len > mstr->sm_strlen); + stp->st_strsize += len - mstr->sm_strlen; } if ((sthash = calloc(sizeof (Str_hash), 1)) == 0) return (-1); mstr->sm_hashval = sthash->hi_hashval = hashval; - mstr->sm_stlen = sthash->hi_stlen = stlen; + mstr->sm_strlen = sthash->hi_strlen = len; mstr->sm_str = str; sthash->hi_refcnt = 1; sthash->hi_mstr = mstr; @@ -543,16 +552,15 @@ st_hash_insert(Str_tbl *stp, const char *str, uint_t stlen) uint_t st_getstrtab_sz(Str_tbl *stp) { - assert(stp->st_fullstringsize > 0); + assert(stp->st_fullstrsize > 0); if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) { stp->st_flags |= FLG_STTAB_COOKED; - return (stp->st_fullstringsize); + return (stp->st_fullstrsize); } - if ((stp->st_flags & FLG_STTAB_COOKED) == 0) { - Stringelem *stelem; + LenNode *lnp; void *cookie; stp->st_flags |= FLG_STTAB_COOKED; @@ -560,77 +568,87 @@ st_getstrtab_sz(Str_tbl *stp) * allocate a hash table about the size of # of * strings input. */ - stp->st_hbckcnt = findprime(stp->st_stringcnt); + stp->st_hbckcnt = findprime(stp->st_strcnt); if ((stp->st_hashbcks = calloc(sizeof (Str_hash), stp->st_hbckcnt)) == NULL) return (0); /* - * We now walk all of the strings in the list, - * from shortest to longest, and insert them into - * the hashtable. + * We now walk all of the strings in the list, from shortest to + * longest, and insert them into the hashtable. */ - if ((stelem = avl_first(stp->st_strtree)) == NULL) { + if ((lnp = avl_first(stp->st_lentree)) == NULL) { /* - * Is it possible we have a empty string table, - * if so - the table still conains '\0' - * so still return the size. + * Is it possible we have an empty string table, if so, + * the table still contains '\0', so return the size. */ - if (avl_numnodes(stp->st_strtree) == 0) { - assert(stp->st_stringsize == 1); - return (stp->st_stringsize); + if (avl_numnodes(stp->st_lentree) == 0) { + assert(stp->st_strsize == 1); + return (stp->st_strsize); } return (0); } - while (stelem) { - Stringlist *strlist, *pstrlist; + + while (lnp) { + StrNode *snp; /* - * Walk the string lists and insert them - * into the hash list. Once a string is - * inserted we no longer need it's entry, - * so free it + * Walk the string lists and insert them into the hash + * list. Once a string is inserted we no longer need + * it's entry, so the string can be freed. */ - for (strlist = stelem->se_strlist, pstrlist = 0; - strlist; strlist = strlist->sl_next) { - if (st_hash_insert(stp, strlist->sl_string, - stelem->se_stlen) == -1) + for (snp = avl_first(lnp->ln_strtree); snp; + snp = AVL_NEXT(lnp->ln_strtree, snp)) { + if (st_hash_insert(stp, snp->sn_str, + lnp->ln_strlen) == -1) return (0); - if (pstrlist) - free(pstrlist); } - free(pstrlist); - stelem->se_strlist = 0; - stelem = AVL_NEXT(stp->st_strtree, stelem); + + /* + * Now that the strings have been copied, walk the + * StrNode tree and free all the AVL nodes. Note, + * avl_destroy_nodes() beats avl_remove() as the + * latter balances the nodes as they are removed. + * We just want to tear the whole thing down fast. + */ + cookie = NULL; + while ((snp = avl_destroy_nodes(lnp->ln_strtree, + &cookie)) != NULL) + free(snp); + avl_destroy(lnp->ln_strtree); + free(lnp->ln_strtree); + lnp->ln_strtree = NULL; + + /* + * Move on to the next LenNode. + */ + lnp = AVL_NEXT(stp->st_lentree, lnp); } /* - * Now that all of the strings have been freed, - * go ahead and quickly re-walk the AVL tree and - * free all of the AVL nodes. - * - * avl_destroy_nodes() beats avl_remove() because - * avl_remove will 'ballance' the tree as nodes - * are deleted - we just want to tear the whole - * thing down now. + * Now that all of the strings have been freed, walk the + * LenNode tree and free all of the AVL nodes. Note, + * avl_destroy_nodes() beats avl_remove() as the latter + * balances the nodes as they are removed. We just want to + * tear the whole thing down fast. */ cookie = NULL; - while ((stelem = avl_destroy_nodes(stp->st_strtree, + while ((lnp = avl_destroy_nodes(stp->st_lentree, &cookie)) != NULL) - free(stelem); - avl_destroy(stp->st_strtree); - free(stp->st_strtree); - stp->st_strtree = 0; + free(lnp); + avl_destroy(stp->st_lentree); + free(stp->st_lentree); + stp->st_lentree = 0; } - assert(stp->st_stringsize > 0); - assert(stp->st_fullstringsize >= stp->st_stringsize); + assert(stp->st_strsize > 0); + assert(stp->st_fullstrsize >= stp->st_strsize); - return (stp->st_stringsize); + return (stp->st_strsize); } /* - * Associate a buffer with the string table. + * Associate a buffer with a string table. */ const char * st_getstrbuf(Str_tbl *stp) @@ -644,10 +662,10 @@ st_setstrbuf(Str_tbl *stp, char *stbuf, uint_t bufsize) assert(stp->st_flags & FLG_STTAB_COOKED); if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0) { - if (bufsize < stp->st_fullstringsize) + if (bufsize < stp->st_fullstrsize) return (-1); } else { - if (bufsize < stp->st_stringsize) + if (bufsize < stp->st_strsize) return (-1); } |
