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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <dlfcn.h> 31 #include <libelf.h> 32 #include <link.h> 33 #include <debug.h> 34 #include "msg.h" 35 #include "_libld.h" 36 37 /* 38 * Table which defines the default functions to be called by the library 39 * SUPPORT (-S <libname>). These functions can be redefined by the 40 * ld_support_loadso() routine. 41 */ 42 static Support_list support[LDS_NUM] = { 43 {MSG_ORIG(MSG_SUP_VERSION), { 0, 0 }}, /* LDS_VERSION */ 44 {MSG_ORIG(MSG_SUP_INPUT_DONE), { 0, 0 }}, /* LDS_INPUT_DONE */ 45 #if defined(_ELF64) 46 {MSG_ORIG(MSG_SUP_START_64), { 0, 0 }}, /* LDS_START */ 47 {MSG_ORIG(MSG_SUP_ATEXIT_64), { 0, 0 }}, /* LDS_ATEXIT */ 48 {MSG_ORIG(MSG_SUP_FILE_64), { 0, 0 }}, /* LDS_FILE */ 49 {MSG_ORIG(MSG_SUP_INSEC_64), { 0, 0 }}, /* LDS_INSEC */ 50 {MSG_ORIG(MSG_SUP_SEC_64), { 0, 0 }} /* LDS_SEC */ 51 #else /* Elf32 */ 52 {MSG_ORIG(MSG_SUP_START), { 0, 0 }}, /* LDS_START */ 53 {MSG_ORIG(MSG_SUP_ATEXIT), { 0, 0 }}, /* LDS_ATEXIT */ 54 {MSG_ORIG(MSG_SUP_FILE), { 0, 0 }}, /* LDS_FILE */ 55 {MSG_ORIG(MSG_SUP_INSEC), { 0, 0 }}, /* LDS_INSEC */ 56 {MSG_ORIG(MSG_SUP_SEC), { 0, 0 }} /* LDS_SEC */ 57 #endif 58 }; 59 60 /* 61 * Loads in a support shared object specified using the SGS_SUPPORT environment 62 * variable or the -S ld option, and determines which interface functions are 63 * provided by that object. 64 */ 65 uintptr_t 66 ld_sup_loadso(Ofl_desc *ofl, const char *obj) 67 { 68 void *handle, (*fptr)(); 69 Func_list *flp; 70 uint_t interface, version = LD_SUP_VERSION1; 71 72 /* 73 * Load the required support library. If we are unable to load it fail 74 * with a fatal error. 75 */ 76 if ((handle = dlopen(obj, (RTLD_LAZY | RTLD_FIRST))) == NULL) { 77 eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD), 78 obj, dlerror()); 79 return (S_ERROR); 80 } 81 82 for (interface = 0; interface < LDS_NUM; interface++) { 83 if ((fptr = (void (*)())dlsym(handle, 84 support[interface].sup_name)) == NULL) 85 continue; 86 87 if ((flp = libld_malloc(sizeof (Func_list))) == NULL) 88 return (S_ERROR); 89 90 flp->fl_obj = obj; 91 flp->fl_fptr = fptr; 92 DBG_CALL(Dbg_support_load(ofl->ofl_lml, obj, 93 support[interface].sup_name)); 94 95 if (interface == LDS_VERSION) { 96 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 97 support[LDS_VERSION].sup_name, LDS_VERSION, 0)); 98 99 version = ((uint_t(*)())flp->fl_fptr)(LD_SUP_VCURRENT); 100 if ((version == LD_SUP_VNONE) || 101 (version > LD_SUP_VCURRENT)) { 102 eprintf(ofl->ofl_lml, ERR_FATAL, 103 MSG_INTL(MSG_SUP_BADVERSION), 104 LD_SUP_VCURRENT, version); 105 (void) dlclose(handle); 106 return (S_ERROR); 107 } 108 } 109 flp->fl_version = version; 110 if (list_appendc(&support[interface].sup_funcs, flp) == 0) 111 return (S_ERROR); 112 } 113 return (1); 114 } 115 116 /* 117 * Wrapper routines for the ld support library calls. 118 */ 119 void 120 ld_sup_start(Ofl_desc *ofl, const Half etype, const char *caller) 121 { 122 Func_list *flp; 123 Listnode *lnp; 124 125 for (LIST_TRAVERSE(&support[LDS_START].sup_funcs, lnp, flp)) { 126 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 127 support[LDS_START].sup_name, LDS_START, ofl->ofl_name)); 128 (*flp->fl_fptr)(ofl->ofl_name, etype, caller); 129 } 130 } 131 132 void 133 ld_sup_atexit(Ofl_desc *ofl, int ecode) 134 { 135 Func_list *flp; 136 Listnode *lnp; 137 138 for (LIST_TRAVERSE(&support[LDS_ATEXIT].sup_funcs, lnp, flp)) { 139 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 140 support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0)); 141 (*flp->fl_fptr)(ecode); 142 } 143 } 144 145 void 146 ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags, 147 Elf *elf) 148 { 149 Func_list *flp; 150 Listnode *lnp; 151 152 for (LIST_TRAVERSE(&support[LDS_FILE].sup_funcs, lnp, flp)) { 153 int _flags = 0; 154 155 if (!(flags & FLG_IF_CMDLINE)) 156 _flags |= LD_SUP_DERIVED; 157 if (!(flags & FLG_IF_NEEDED)) 158 _flags |= LD_SUP_INHERITED; 159 if (flags & FLG_IF_EXTRACT) 160 _flags |= LD_SUP_EXTRACTED; 161 162 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 163 support[LDS_FILE].sup_name, LDS_FILE, ifile)); 164 (*flp->fl_fptr)(ifile, ekind, _flags, elf); 165 } 166 } 167 168 uintptr_t 169 ld_sup_input_section(Ofl_desc *ofl, Ifl_desc *ifl, const char *sname, 170 Shdr **oshdr, Word ndx, Elf_Scn *scn, Elf *elf) 171 { 172 Func_list *flp; 173 Listnode *lnp; 174 uint_t flags = 0; 175 Elf_Data *data = NULL; 176 Shdr *nshdr = *oshdr; 177 178 for (LIST_TRAVERSE(&support[LDS_INSEC].sup_funcs, lnp, flp)) { 179 /* 180 * This interface was introduced in VERSION2. Only call this 181 * function for libraries reporting support for version 2 or 182 * above. 183 */ 184 if (flp->fl_version < LD_SUP_VERSION2) 185 continue; 186 187 if ((data == NULL) && 188 ((data = elf_getdata(scn, NULL)) == NULL)) { 189 eprintf(ofl->ofl_lml, ERR_ELF, 190 MSG_INTL(MSG_ELF_GETDATA), ifl->ifl_name); 191 ofl->ofl_flags |= FLG_OF_FATAL; 192 return (S_ERROR); 193 } 194 195 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 196 support[LDS_INSEC].sup_name, LDS_INSEC, sname)); 197 (*flp->fl_fptr)(sname, &nshdr, ndx, data, elf, &flags); 198 } 199 200 /* 201 * If the section header has been re-allocated (known to occur with 202 * libCCexcept.so), then diagnose the section header difference and 203 * return the new section header. 204 */ 205 if (nshdr != *oshdr) { 206 Dbg_shdr_modified(ofl->ofl_lml, ifl->ifl_ehdr->e_machine, 207 *oshdr, nshdr, sname); 208 *oshdr = nshdr; 209 } 210 return (0); 211 } 212 213 void 214 ld_sup_section(Ofl_desc *ofl, const char *scn, Shdr *shdr, Word ndx, 215 Elf_Data *data, Elf *elf) 216 { 217 Func_list *flp; 218 Listnode *lnp; 219 220 for (LIST_TRAVERSE(&support[LDS_SEC].sup_funcs, lnp, flp)) { 221 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 222 support[LDS_SEC].sup_name, LDS_SEC, scn)); 223 (*flp->fl_fptr)(scn, shdr, ndx, data, elf); 224 } 225 } 226 227 void 228 ld_sup_input_done(Ofl_desc *ofl) 229 { 230 Func_list *flp; 231 Listnode *lnp; 232 uint_t flags = 0; 233 234 for (LIST_TRAVERSE(&support[LDS_INPUT_DONE].sup_funcs, lnp, flp)) { 235 /* 236 * This interface was introduced in VERSION2. Only call this 237 * function for libraries reporting support for version 2 or 238 * above. 239 */ 240 if (flp->fl_version < LD_SUP_VERSION2) 241 continue; 242 243 DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 244 support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0)); 245 (*flp->fl_fptr)(&flags); 246 } 247 } 248