1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <unistd.h> 28 #include <stdio.h> 29 #include <stdarg.h> 30 #include "msg.h" 31 #include "_libld.h" 32 33 /* 34 * GNU ld --wrap support, also known as -z wrap. 35 * 36 * We maintain an AVL tree of wrapped symbol names. Every undefined 37 * symbol is tested against this tree, and those that match have 38 * their names modified to produce the wrapping effect: 39 * 40 * - An undefined reference to XXX is converted to __wrap_XXX 41 * - An undefined reference to __real_XXX is converted to XXX 42 * 43 * This operation has a cost, but that is mitigated by two factors: 44 * 45 * - This is a test feature, not used for production code, so somewhat 46 * longer link times are tolerable. 47 * - The cost of this feature is only paid when it is used. Otherwise, 48 * the sole overhead is the cost of testing the NULL AVL tree pointer 49 * during symbol processing. 50 */ 51 52 53 /* 54 * AVL comparison function for WrapSymNode items. 55 * 56 * entry: 57 * n1, n2 - pointers to nodes to be compared 58 * 59 * exit: 60 * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2) 61 */ 62 static int 63 wrap_cmp(const void *n1, const void *n2) 64 { 65 int rc; 66 67 rc = strcmp(((WrapSymNode *)n1)->wsn_name, 68 ((WrapSymNode *)n2)->wsn_name); 69 70 if (rc > 0) 71 return (1); 72 if (rc < 0) 73 return (-1); 74 return (0); 75 } 76 77 /* 78 * Enter a -z wrap symbol into the ofl_wrap AVL tree 79 * 80 * entry: 81 * ofl - Output file descriptor 82 * name - Name of symbol to be entered. Caller must ensure that 83 * memory used to hold name remains available for the life 84 * of the link-edit process. 85 * 86 * exit: 87 * On success, updates ofl->wrap_cache with a pointer to the 88 * resulting WrapSymNode, and returns that pointer. On failure, 89 * returns NULL. 90 */ 91 WrapSymNode * 92 ld_wrap_enter(Ofl_desc *ofl, const char *name) 93 { 94 WrapSymNode *wsnp, wsn; 95 avl_index_t where; 96 size_t name_len, wrapname_len; 97 char *tmpname; 98 99 /* If this is the first wrap symbol, create the AVL tree */ 100 if (ofl->ofl_wrap == NULL) { 101 ofl->ofl_wrap = libld_calloc(1, sizeof (*ofl->ofl_wrap)); 102 if (ofl->ofl_wrap == NULL) 103 return (NULL); 104 avl_create(ofl->ofl_wrap, wrap_cmp, sizeof (WrapSymNode), 105 SGSOFFSETOF(WrapSymNode, wsn_avlnode)); 106 } 107 108 /* Have we already entered this one? */ 109 wsn.wsn_name = name; 110 if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, &where)) != NULL) 111 return (wsnp); 112 113 /* 114 * Allocate a new node, along with room for the wrapped name. 115 * Since strings have byte alignment, we can allocate it immediately 116 * following the AVL node without the need for alignment padding. 117 */ 118 name_len = strlen(wsn.wsn_name); 119 wrapname_len = MSG_STR_UU_WRAP_U_SIZE + name_len + 1; 120 if ((wsnp = libld_calloc(1, sizeof (*wsnp) + wrapname_len)) == NULL) 121 return (NULL); 122 wsnp->wsn_name = name; 123 124 wsnp->wsn_wrapname = tmpname = (char *)(wsnp + 1); 125 (void) snprintf(tmpname, wrapname_len, MSG_ORIG(MSG_FMT_STRCAT), 126 MSG_ORIG(MSG_STR_UU_WRAP_U), name); 127 128 /* Insert the new node */ 129 avl_insert(ofl->ofl_wrap, wsnp, where); 130 return (wsnp); 131 } 132