cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami/*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * CDDL HEADER START
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * The contents of this file are subject to the terms of the
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Common Development and Distribution License (the "License").
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * You may not use this file except in compliance with the License.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * or http://www.opensolaris.org/os/licensing.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * See the License for the specific language governing permissions
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * and limitations under the License.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * When distributing Covered Code, include this CDDL HEADER in each
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * If applicable, add the following below this CDDL HEADER, with the
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * fields enclosed by brackets "[]" replaced with your own identifying
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * information: Portions Copyright [yyyy] [name of copyright owner]
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * CDDL HEADER END
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami/*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Use is subject to license terms.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami#include <unistd.h>
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami#include <stdio.h>
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami#include <stdarg.h>
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami#include "msg.h"
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami#include "_libld.h"
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami/*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * GNU ld --wrap support, also known as -z wrap.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * We maintain an AVL tree of wrapped symbol names. Every undefined
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * symbol is tested against this tree, and those that match have
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * their names modified to produce the wrapping effect:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * - An undefined reference to XXX is converted to __wrap_XXX
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * - An undefined reference to __real_XXX is converted to XXX
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * This operation has a cost, but that is mitigated by two factors:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * - This is a test feature, not used for production code, so somewhat
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * longer link times are tolerable.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * - The cost of this feature is only paid when it is used. Otherwise,
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * the sole overhead is the cost of testing the NULL AVL tree pointer
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * during symbol processing.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami/*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * AVL comparison function for WrapSymNode items.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * entry:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * n1, n2 - pointers to nodes to be compared
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * exit:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahramistatic int
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahramiwrap_cmp(const void *n1, const void *n2)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami{
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami int rc;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami rc = strcmp(((WrapSymNode *)n1)->wsn_name,
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami ((WrapSymNode *)n2)->wsn_name);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if (rc > 0)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (1);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if (rc < 0)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (-1);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (0);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami}
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami/*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Enter a -z wrap symbol into the ofl_wrap AVL tree
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * entry:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * ofl - Output file descriptor
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * name - Name of symbol to be entered. Caller must ensure that
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * memory used to hold name remains available for the life
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * of the link-edit process.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * exit:
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * On success, updates ofl->wrap_cache with a pointer to the
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * resulting WrapSymNode, and returns that pointer. On failure,
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * returns NULL.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali BahramiWrapSymNode *
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahramild_wrap_enter(Ofl_desc *ofl, const char *name)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami{
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami WrapSymNode *wsnp, wsn;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami avl_index_t where;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami size_t name_len, wrapname_len;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami char *tmpname;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami /* If this is the first wrap symbol, create the AVL tree */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if (ofl->ofl_wrap == NULL) {
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami ofl->ofl_wrap = libld_calloc(1, sizeof (*ofl->ofl_wrap));
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if (ofl->ofl_wrap == NULL)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (NULL);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami avl_create(ofl->ofl_wrap, wrap_cmp, sizeof (WrapSymNode),
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami SGSOFFSETOF(WrapSymNode, wsn_avlnode));
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami }
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami /* Have we already entered this one? */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami wsn.wsn_name = name;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, &where)) != NULL)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (wsnp);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami /*
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Allocate a new node, along with room for the wrapped name.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * Since strings have byte alignment, we can allocate it immediately
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami * following the AVL node without the need for alignment padding.
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami name_len = strlen(wsn.wsn_name);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami wrapname_len = MSG_STR_UU_WRAP_U_SIZE + name_len + 1;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami if ((wsnp = libld_calloc(1, sizeof (*wsnp) + wrapname_len)) == NULL)
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (NULL);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami wsnp->wsn_name = name;
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami wsnp->wsn_wrapname = tmpname = (char *)(wsnp + 1);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami (void) snprintf(tmpname, wrapname_len, MSG_ORIG(MSG_FMT_STRCAT),
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami MSG_ORIG(MSG_STR_UU_WRAP_U), name);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami /* Insert the new node */
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami avl_insert(ofl->ofl_wrap, wsnp, where);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami return (wsnp);
cdcc71c09dccd8c66f98c710f068f0722fe6de56Ali Bahrami}