Mercurial > illumos > illumos-gate
changeset 10580:030e7fb9c81f
6850768 ld option to autogenerate wrappers/interposers similar to GNU ld --wrap
PSARC/2009/493 ld -z wrap option
author | Ali Bahrami <Ali.Bahrami@Sun.COM> |
---|---|
date | Fri, 18 Sep 2009 09:00:12 -0600 |
parents | 1cdfcf4400ac |
children | c2151e45dda5 |
files | usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/libld/Makefile.com usr/src/cmd/sgs/libld/common/_libld.h usr/src/cmd/sgs/libld/common/args.c usr/src/cmd/sgs/libld/common/ldmain.c usr/src/cmd/sgs/libld/common/libld.msg usr/src/cmd/sgs/libld/common/syms.c usr/src/cmd/sgs/libld/common/util.c usr/src/cmd/sgs/libld/common/wrap.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/liblddbg/common/syms.c usr/src/cmd/sgs/packages/common/SUNWonld-README |
diffstat | 15 files changed, 342 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/sgs/include/debug.h Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/include/debug.h Fri Sep 18 09:00:12 2009 -0600 @@ -424,6 +424,7 @@ #define Dbg_syms_spec_title Dbg64_syms_spec_title #define Dbg_syms_updated Dbg64_syms_updated #define Dbg_syms_up_title Dbg64_syms_up_title +#define Dbg_syms_wrap Dbg64_syms_wrap #define Dbg_util_call_array Dbg64_util_call_array #define Dbg_util_call_fini Dbg64_util_call_fini @@ -632,6 +633,7 @@ #define Dbg_syms_spec_title Dbg32_syms_spec_title #define Dbg_syms_updated Dbg32_syms_updated #define Dbg_syms_up_title Dbg32_syms_up_title +#define Dbg_syms_wrap Dbg32_syms_wrap #define Dbg_util_call_array Dbg32_util_call_array #define Dbg_util_call_fini Dbg32_util_call_fini @@ -896,6 +898,7 @@ extern void Dbg_syms_spec_title(Lm_list *); extern void Dbg_syms_updated(Ofl_desc *, Sym_desc *, const char *); extern void Dbg_syms_up_title(Lm_list *); +extern void Dbg_syms_wrap(Lm_list *, Word, const char *, const char *); extern void Dbg_tls_modactivity(Lm_list *, void *, uint_t); extern void Dbg_tls_static_block(Lm_list *, void *, ulong_t, ulong_t);
--- a/usr/src/cmd/sgs/include/libld.h Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/include/libld.h Fri Sep 18 09:00:12 2009 -0600 @@ -150,6 +150,20 @@ } Rlxrel_cache; /* + * Nodes in an ofl_wrap AVL tree + * + * wsn_name is the name of the symbol to be wrapped. wsn_wrapname is used + * when we need to refer to the wrap symbol, and consists of the symbol + * name with a __wrap_ prefix. + */ +typedef struct wrap_sym_node { + avl_node_t wsn_avlnode; /* AVL book-keeping */ + const char *wsn_name; /* Symbol name: XXX */ + const char *wsn_wrapname; /* Wrap symbol name: __wrap_XXX */ +} WrapSymNode; + + +/* * Output file processing structure */ typedef Lword ofl_flag_t; @@ -304,6 +318,7 @@ /* sloppy_comdat_reloc() */ APlist *ofl_maptext; /* mapfile added text sections */ APlist *ofl_mapdata; /* mapfile added data sections */ + avl_tree_t *ofl_wrap; /* -z wrap symbols */ }; #define FLG_OF_DYNAMIC 0x00000001 /* generate dynamic output module */
--- a/usr/src/cmd/sgs/libld/Makefile.com Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/Makefile.com Fri Sep 18 09:00:12 2009 -0600 @@ -33,14 +33,14 @@ libs32.o files32.o map32.o order32.o \ outfile32.o place32.o relocate32.o resolve32.o \ sections32.o sunwmove32.o support32.o syms32.o \ - update32.o unwind32.o version32.o + update32.o unwind32.o version32.o wrap32.o COMOBJS64 = args64.o entry64.o exit64.o groups64.o \ ldentry64.o ldlibs64.o ldmachdep64.o ldmain64.o \ libs64.o files64.o map64.o order64.o \ outfile64.o place64.o relocate64.o resolve64.o \ sections64.o sunwmove64.o support64.o syms64.o \ - update64.o unwind64.o version64.o + update64.o unwind64.o version64.o wrap64.o TOOLOBJS = alist.o assfail.o findprime.o string_table.o \ strhash.o
--- a/usr/src/cmd/sgs/libld/common/_libld.h Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/_libld.h Fri Sep 18 09:00:12 2009 -0600 @@ -616,6 +616,7 @@ #define ld_vers_promote ld64_vers_promote #define ld_vers_sym_process ld64_vers_sym_process #define ld_vers_verify ld64_vers_verify +#define ld_wrap_enter ld64_wrap_enter #else @@ -703,6 +704,7 @@ #define ld_vers_promote ld32_vers_promote #define ld_vers_sym_process ld32_vers_sym_process #define ld_vers_verify ld32_vers_verify +#define ld_wrap_enter ld32_wrap_enter #endif @@ -831,6 +833,7 @@ Ofl_desc *); extern int ld_vers_sym_process(Lm_list *, Is_desc *, Ifl_desc *); extern int ld_vers_verify(Ofl_desc *); +extern WrapSymNode *ld_wrap_enter(Ofl_desc *, const char *); extern uintptr_t add_regsym(Sym_desc *, Ofl_desc *); extern Word hashbkts(Word);
--- a/usr/src/cmd/sgs/libld/common/args.c Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/args.c Fri Sep 18 09:00:12 2009 -0600 @@ -55,6 +55,21 @@ * -z nosighandler suppress the registration of the signal handler * used to manage SIGBUS. */ + +/* + * The following flags are committed, and will not be removed, but are + * not publically documented, either because they are obsolete, or because + * they exist to work around defects in other software and are not of + * sufficient interest otherwise. + * + * OPTION MEANING + * + * -Wl,... compiler drivers and configuration tools + * have been known to pass this compiler option + * to ld(1). Strip off the "-Wl," prefix and + * process the remainder (...) as a normal option. + */ + #include <sys/link.h> #include <stdio.h> #include <fcntl.h> @@ -198,6 +213,7 @@ (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZT)); (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTO)); (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZTW)); + (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZWRAP)); (void) fprintf(stderr, MSG_INTL(MSG_ARG_DETAIL_ZV)); } @@ -1299,6 +1315,17 @@ /* Don't report cascading errors */ ofl->ofl_ars_gsandx = -1; } + + /* + * If -z wrap is seen, enter the symbol to be wrapped + * into the wrap AVL tree. + */ + } else if (strncmp(optarg, MSG_ORIG(MSG_ARG_WRAP), + MSG_ARG_WRAP_SIZE) == 0) { + if (ld_wrap_enter(ofl, + optarg + MSG_ARG_WRAP_SIZE) == NULL) + return (S_ERROR); + /* * The following options just need validation as they * are interpreted on the second pass through the
--- a/usr/src/cmd/sgs/libld/common/ldmain.c Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/ldmain.c Fri Sep 18 09:00:12 2009 -0600 @@ -404,9 +404,8 @@ * our memory consumption and freeing are doing. We should be able to * free all the memory that has been allocated as part of the link-edit * process. - * - * ofl_cleanup(ofl); */ + /* ld_ofl_cleanup(ofl); */ return (0); }
--- a/usr/src/cmd/sgs/libld/common/libld.msg Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/libld.msg Fri Sep 18 09:00:12 2009 -0600 @@ -228,6 +228,8 @@ text\n" @ MSG_ARG_DETAIL_ZTW "\t[-z textwarn]\twarn if there are relocations \ against text\n" +@ MSG_ARG_DETAIL_ZWRAP "\t[-z wrap=symbol], [-wrap=symbol], [--wrap=symbol]\n\ + \t\t\twrap symbol references\n" @ MSG_ARG_DETAIL_ZV "\t[-z verbose]\t\ generate warnings for suspicious processings\n" @@ -652,11 +654,14 @@ @ MSG_STR_ISALIST "$ISALIST" @ MSG_STR_OSNAME "$OSNAME" @ MSG_STR_OSREL "$OSREL" +@ MSG_STR_UU_REAL_U "__real_" +@ MSG_STR_UU_WRAP_U "__wrap_" @ MSG_FMT_ARMEM "%s(%s)" @ MSG_FMT_COLPATH "%s:%s" @ MSG_FMT_SYMNAM "`%s'" @ MSG_FMT_NULLSYMNAM "%s[%d]" +@ MSG_FMT_STRCAT "%s%s" @ MSG_PTH_RTLD "/usr/lib/ld.so.1" @@ -1210,6 +1215,7 @@ @ MSG_ARG_NOSIGHANDLER "nosighandler" @ MSG_ARG_GLOBAUDIT "globalaudit" @ MSG_ARG_TARGET "target=" +@ MSG_ARG_WRAP "wrap=" @ MSG_ARG_HELP "help" @ MSG_ARG_GROUP "group" @ MSG_ARG_REDUCE "reduce" @@ -1242,6 +1248,7 @@ @ MSG_ARG_T_UNDEF "-undefined" @ MSG_ARG_T_VERSION "-version" @ MSG_ARG_T_WHOLEARC "-whole-archive" +@ MSG_ARG_T_WRAP "-wrap" @ MSG_ARG_T_OPAR "(" @ MSG_ARG_T_CPAR ")"
--- a/usr/src/cmd/sgs/libld/common/syms.c Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/syms.c Fri Sep 18 09:00:12 2009 -0600 @@ -2312,6 +2312,48 @@ } /* + * The '-z wrap=XXX' option emulates the GNU ld --wrap=XXX + * option. When XXX is the symbol to be wrapped: + * + * - An undefined reference to XXX is converted to __wrap_XXX + * - An undefined reference to __real_XXX is converted to XXX + * + * The idea is that the user can supply a wrapper function + * __wrap_XXX that does some work, and then uses the name + * __real_XXX to pass the call on to the real function. The + * wrapper objects are linked with the original unmodified + * objects to produce a wrapped version of the output object. + */ + if (ofl->ofl_wrap && name[0] && (shndx == SHN_UNDEF)) { + WrapSymNode wsn, *wsnp; + + /* + * If this is the __real_XXX form, advance the + * pointer to reference the wrapped name. + */ + wsn.wsn_name = name; + if ((*name == '_') && + (strncmp(name, MSG_ORIG(MSG_STR_UU_REAL_U), + MSG_STR_UU_REAL_U_SIZE) == 0)) + wsn.wsn_name += MSG_STR_UU_REAL_U_SIZE; + + /* + * Is this symbol in the wrap AVL tree? If so, map + * XXX to __wrap_XXX, and __real_XXX to XXX. Note that + * wsn.wsn_name will equal the current value of name + * if the __real_ prefix is not present. + */ + if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, 0)) != NULL) { + const char *old_name = name; + + name = (wsn.wsn_name == name) ? + wsnp->wsn_wrapname : wsn.wsn_name; + DBG_CALL(Dbg_syms_wrap(ofl->ofl_lml, ndx, + old_name, name)); + } + } + + /* * Determine and validate the symbols binding. */ bind = ELF_ST_BIND(sym->st_info);
--- a/usr/src/cmd/sgs/libld/common/util.c Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/libld/common/util.c Fri Sep 18 09:00:12 2009 -0600 @@ -279,13 +279,48 @@ } /* + * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our + * '-z wrap=XXX'. When str2chr() does this conversion, we end up with + * the return character set to 'z' and optarg set to 'XXX'. This callback + * changes optarg to include the missing wrap= prefix. + * + * exit: + * Returns c on success, or '?' on error. + */ +static int +str2chr_wrap_cb(int c) +{ + char *str; + size_t len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1; + + if ((str = libld_malloc(len)) == NULL) + return ('?'); + (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT), + MSG_ORIG(MSG_ARG_WRAP), optarg); + optarg = str; + return (c); +} + +/* * Determine whether this string, possibly with an associated option, should be * translated to an option character. If so, update the optind and optarg * as described for short options in getopt(3c). + * + * entry: + * lml - Link map list for debug messages + * ndx - Starting optind for current item + * argc, argv - Command line arguments + * arg - Option to be examined + * c, opt - Option character (c) and corresponding long name (opt) + * optsz - 0 if option does not accept a value. If option does + * accept a value, strlen(opt), giving the offset to the + * value if the option and value are combined in one string. + * cbfunc - NULL, or pointer to function to call if a translation is + * successful. */ static int str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c, - const char *opt, size_t optsz) + const char *opt, size_t optsz, int cbfunc(int)) { if (optsz == 0) { /* @@ -331,6 +366,10 @@ return ('?'); } } + + if (cbfunc != NULL) + c = (*cbfunc)(c); + return (c); } return (0); @@ -362,20 +401,28 @@ /* Translate -rpath <optarg> to -R <optarg> */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'R', MSG_ORIG(MSG_ARG_T_RPATH), - MSG_ARG_T_RPATH_SIZE)) != 0) { + MSG_ARG_T_RPATH_SIZE, NULL)) != 0) { return (c); } break; case 's': /* Translate -shared to -G */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'G', - MSG_ORIG(MSG_ARG_T_SHARED), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) { return (c); /* Translate -soname <optarg> to -h <optarg> */ } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h', MSG_ORIG(MSG_ARG_T_SONAME), - MSG_ARG_T_SONAME_SIZE)) != 0) { + MSG_ARG_T_SONAME_SIZE, NULL)) != 0) { + return (c); + } + break; + case 'w': + /* Translate -wrap to -z wrap= */ + if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', + MSG_ORIG(MSG_ARG_T_WRAP) + 1, + MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) { return (c); } break; @@ -384,7 +431,8 @@ * Translate -( to -z rescan-start */ if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) != + 0) { optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START); return (c); } @@ -394,7 +442,8 @@ * Translate -) to -z rescan-end */ if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) != + 0) { optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END); return (c); } @@ -407,7 +456,8 @@ * -zmuldefs */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', - MSG_ORIG(MSG_ARG_T_MULDEFS), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) != + 0) { optarg = (char *)MSG_ORIG(MSG_ARG_MULDEFS); return (c); @@ -418,7 +468,7 @@ */ } else if ((c = str2chr(lml, argc, ndx, argv, arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR), - MSG_ARG_T_AUXFLTR_SIZE)) != 0) { + MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) { return (c); } break; @@ -429,7 +479,7 @@ */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'I', MSG_ORIG(MSG_ARG_T_INTERP), - MSG_ARG_T_INTERP_SIZE)) != 0) { + MSG_ARG_T_INTERP_SIZE, NULL)) != 0) { return (c); } break; @@ -437,15 +487,15 @@ /* Translate --entry <optarg> to -e <optarg> */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'e', MSG_ORIG(MSG_ARG_T_ENTRY), - MSG_ARG_T_ENTRY_SIZE)) != 0) { + MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) { return (c); } /* * Translate --end-group to -z rescan-end */ if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', - MSG_ORIG(MSG_ARG_T_ENDGROUP), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP), + 0, NULL)) != 0) { optarg = (char *) MSG_ORIG(MSG_ARG_RESCAN_END); return (c); @@ -455,14 +505,15 @@ /* Translate --filter <optarg> to -F <optarg> */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'F', MSG_ORIG(MSG_ARG_T_STDFLTR), - MSG_ARG_T_STDFLTR_SIZE)) != 0) { + MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) { return (c); } break; case 'h': /* Translate --help to -zhelp */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', - MSG_ORIG(MSG_ARG_T_HELP), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) != + 0) { optarg = (char *)MSG_ORIG(MSG_ARG_HELP); return (c); } @@ -473,7 +524,7 @@ */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'l', MSG_ORIG(MSG_ARG_T_LIBRARY), - MSG_ARG_T_LIBRARY_SIZE)) != 0) { + MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) { return (c); /* @@ -482,14 +533,15 @@ */ } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH), - MSG_ARG_T_LIBPATH_SIZE)) != 0) { + MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) { return (c); } break; case 'n': /* Translate --no-undefined to -zdefs */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', - MSG_ORIG(MSG_ARG_T_NOUNDEF), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) != + 0) { optarg = (char *)MSG_ORIG(MSG_ARG_DEFS); return (c); @@ -498,8 +550,8 @@ * -z defaultextract */ } else if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', - MSG_ORIG(MSG_ARG_T_NOWHOLEARC), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC), + 0, NULL)) != 0) { optarg = (char *)MSG_ORIG(MSG_ARG_DFLEXTRT); return (c); @@ -509,29 +561,31 @@ /* Translate --output <optarg> to -o <optarg> */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'o', MSG_ORIG(MSG_ARG_T_OUTPUT), - MSG_ARG_T_OUTPUT_SIZE)) != 0) { + MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) { return (c); } break; case 'r': /* Translate --relocatable to -r */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'r', - MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0, + NULL)) != 0) { return (c); } break; case 's': /* Translate --strip-all to -s */ if ((c = str2chr(lml, ndx, argc, argv, arg, 's', - MSG_ORIG(MSG_ARG_T_STRIP), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) != + 0) { return (c); } /* * Translate --start-group to -z rescan-start */ if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', - MSG_ORIG(MSG_ARG_T_STARTGROUP), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP), + 0, NULL)) != 0) { optarg = (char *) MSG_ORIG(MSG_ARG_RESCAN_START); return (c); @@ -544,14 +598,15 @@ */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'u', MSG_ORIG(MSG_ARG_T_UNDEF), - MSG_ARG_T_UNDEF_SIZE)) != 0) { + MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) { return (c); } break; case 'v': /* Translate --version to -V */ if ((c = str2chr(lml, ndx, argc, argv, arg, 'V', - MSG_ORIG(MSG_ARG_T_VERSION), 0)) != 0) { + MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) != + 0) { return (c); } break; @@ -560,17 +615,27 @@ * Translate --whole-archive to -z alltextract */ if ((c = str2chr(lml, ndx, argc, argv, - arg, 'z', - MSG_ORIG(MSG_ARG_T_WHOLEARC), 0)) != 0) { + arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC), + 0, NULL)) != 0) { optarg = (char *)MSG_ORIG(MSG_ARG_ALLEXTRT); return (c); } + /* + * Translate --wrap to -z wrap= + */ + if ((c = str2chr(lml, ndx, argc, argv, + arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP), + MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) != + 0) { + return (c); + } break; } break; } } + if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { /* * It is possible that a "-Wl," argument has been used to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libld/common/wrap.c Fri Sep 18 09:00:12 2009 -0600 @@ -0,0 +1,131 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include "msg.h" +#include "_libld.h" + +/* + * GNU ld --wrap support, also known as -z wrap. + * + * We maintain an AVL tree of wrapped symbol names. Every undefined + * symbol is tested against this tree, and those that match have + * their names modified to produce the wrapping effect: + * + * - An undefined reference to XXX is converted to __wrap_XXX + * - An undefined reference to __real_XXX is converted to XXX + * + * This operation has a cost, but that is mitigated by two factors: + * + * - This is a test feature, not used for production code, so somewhat + * longer link times are tolerable. + * - The cost of this feature is only paid when it is used. Otherwise, + * the sole overhead is the cost of testing the NULL AVL tree pointer + * during symbol processing. + */ + + +/* + * AVL comparison function for WrapSymNode items. + * + * entry: + * n1, n2 - pointers to nodes to be compared + * + * exit: + * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2) + */ +static int +wrap_cmp(const void *n1, const void *n2) +{ + int rc; + + rc = strcmp(((WrapSymNode *)n1)->wsn_name, + ((WrapSymNode *)n2)->wsn_name); + + if (rc > 0) + return (1); + if (rc < 0) + return (-1); + return (0); +} + +/* + * Enter a -z wrap symbol into the ofl_wrap AVL tree + * + * entry: + * ofl - Output file descriptor + * name - Name of symbol to be entered. Caller must ensure that + * memory used to hold name remains available for the life + * of the link-edit process. + * + * exit: + * On success, updates ofl->wrap_cache with a pointer to the + * resulting WrapSymNode, and returns that pointer. On failure, + * returns NULL. + */ +WrapSymNode * +ld_wrap_enter(Ofl_desc *ofl, const char *name) +{ + WrapSymNode *wsnp, wsn; + avl_index_t where; + size_t name_len, wrapname_len; + char *tmpname; + + /* If this is the first wrap symbol, create the AVL tree */ + if (ofl->ofl_wrap == NULL) { + ofl->ofl_wrap = libld_calloc(1, sizeof (*ofl->ofl_wrap)); + if (ofl->ofl_wrap == NULL) + return (NULL); + avl_create(ofl->ofl_wrap, wrap_cmp, sizeof (WrapSymNode), + SGSOFFSETOF(WrapSymNode, wsn_avlnode)); + } + + /* Have we already entered this one? */ + wsn.wsn_name = name; + if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, &where)) != NULL) + return (wsnp); + + /* + * Allocate a new node, along with room for the wrapped name. + * Since strings have byte alignment, we can allocate it immediately + * following the AVL node without the need for alignment padding. + */ + name_len = strlen(wsn.wsn_name); + wrapname_len = MSG_STR_UU_WRAP_U_SIZE + name_len + 1; + if ((wsnp = libld_calloc(1, sizeof (*wsnp) + wrapname_len)) == NULL) + return (NULL); + wsnp->wsn_name = name; + + wsnp->wsn_wrapname = tmpname = (char *)(wsnp + 1); + (void) snprintf(tmpname, wrapname_len, MSG_ORIG(MSG_FMT_STRCAT), + MSG_ORIG(MSG_STR_UU_WRAP_U), name); + + /* Insert the new node */ + avl_insert(ofl->ofl_wrap, wsnp, where); + return (wsnp); +}
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Fri Sep 18 09:00:12 2009 -0600 @@ -953,6 +953,7 @@ discarded file=%s" @ MSG_SYM_DISCARD_DUP "symbol[%d]=%s; discarded duplicate: originates from \ file=%s" +@ MSG_SYM_WRAP "symbol[%d]=%s renamed to %s (-z wrap)" @ MSG_SYM_AOUT "symbol=%s; (original AOUT name)" @ MSG_SYM_LOOKUP "symbol=%s; lookup in file=%s [ %s ]"
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Fri Sep 18 09:00:12 2009 -0600 @@ -404,6 +404,8 @@ void Dbg64_syms_updated(Ofl_desc *, Sym_desc *, const char *); void Dbg32_syms_up_title(Lm_list *); void Dbg64_syms_up_title(Lm_list *); +void Dbg32_syms_wrap(Lm_list *, Elf32_Word, const char *, const char *); +void Dbg64_syms_wrap(Lm_list *, Elf64_Word, const char *, const char *); void Dbg32_util_broadcast(Rt_map *); void Dbg64_util_broadcast(Rt_map *);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Fri Sep 18 09:00:12 2009 -0600 @@ -41,7 +41,7 @@ # MAPFILE HEADER END # -SUNWprivate_4.73 { +SUNWprivate_4.74 { global: dbg_desc = NODIRECT; # interposed - ld.so.1(1) dbg_print = NODIRECT; # interposed - ld(1) and ld.so.1(1) @@ -399,6 +399,8 @@ Dbg64_syms_updated; Dbg32_syms_up_title; Dbg64_syms_up_title; + Dbg32_syms_wrap; + Dbg64_syms_wrap; Dbg_tls_modactivity; Dbg_tls_static_block;
--- a/usr/src/cmd/sgs/liblddbg/common/syms.c Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/syms.c Fri Sep 18 09:00:12 2009 -0600 @@ -284,6 +284,16 @@ } void +Dbg_syms_wrap(Lm_list *lml, Word ndx, const char *orig_name, const char *name) +{ + if (DBG_NOTCLASS(DBG_C_SYMBOLS)) + return; + + dbg_print(lml, MSG_INTL(MSG_SYM_WRAP), EC_WORD(ndx), + Dbg_demangle_name(orig_name), Dbg_demangle_name(name)); +} + +void Dbg_syms_sec_title(Lm_list *lml) { if (DBG_NOTCLASS(DBG_C_SYMBOLS))
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Fri Sep 18 01:55:30 2009 -0700 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Fri Sep 18 09:00:12 2009 -0600 @@ -1531,3 +1531,5 @@ 6834197 ld pukes when given an empty plate 6516644 per-symbol filtering shouldn't be allowed in executables 6878605 ld should accept '%' syntax when matching input SHT_PROGBITS sections +6850768 ld option to autogenerate wrappers/interposers similar to GNU ld --wrap + PSARC/2009/493 ld -z wrap option