1 /* $NetBSD: load.c,v 1.15 2001/11/02 15:28:36 skrll Exp $ */ 2 3 /* 4 * Copyright 1996 John D. Polstra. 5 * Copyright 1996 Matt Thomas <matt@3am-software.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by John Polstra. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Dynamic linker for ELF. 36 * 37 * John Polstra <jdp@polstra.com>. 38 */ 39 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <sys/types.h> 49 #include <sys/param.h> 50 #include <sys/mman.h> 51 #include <sys/sysctl.h> 52 #include <dirent.h> 53 54 #include "debug.h" 55 #include "rtld.h" 56 57 static bool _rtld_load_by_name __P((const char *, Obj_Entry *, Needed_Entry **, 58 int, bool)); 59 60 Objlist _rtld_list_global = /* Objects dlopened with RTLD_GLOBAL */ 61 SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global); 62 63 void 64 _rtld_objlist_add(list, obj) 65 Objlist *list; 66 Obj_Entry *obj; 67 { 68 Objlist_Entry *elm; 69 70 elm = NEW(Objlist_Entry); 71 elm->obj = obj; 72 SIMPLEQ_INSERT_TAIL(list, elm, link); 73 } 74 75 Objlist_Entry * 76 _rtld_objlist_find(Objlist *list, const Obj_Entry *obj) 77 { 78 Objlist_Entry *elm; 79 80 for (elm = SIMPLEQ_FIRST(list); elm; elm = SIMPLEQ_NEXT(elm, link)) { 81 if (elm->obj == obj) 82 return elm; 83 } 84 return NULL; 85 } 86 87 /* 88 * Load a shared object into memory, if it is not already loaded. The 89 * argument must be a string allocated on the heap. This function assumes 90 * responsibility for freeing it when necessary. 91 * 92 * Returns a pointer to the Obj_Entry for the object. Returns NULL 93 * on failure. 94 */ 95 Obj_Entry * 96 _rtld_load_object(filepath, mode, dodebug) 97 char *filepath; 98 int mode; 99 bool dodebug; 100 { 101 Obj_Entry *obj; 102 int fd = -1; 103 struct stat sb; 104 105 for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) 106 if (strcmp(obj->path, filepath) == 0) 107 break; 108 109 /* 110 * If we didn't find a match by pathname, open the file and check 111 * again by device and inode. This avoids false mismatches caused 112 * by multiple links or ".." in pathnames. 113 * 114 * To avoid a race, we open the file and use fstat() rather than 115 * using stat(). 116 */ 117 if (obj == NULL) { 118 if ((fd = open(filepath, O_RDONLY)) == -1) { 119 _rtld_error("Cannot open \"%s\"", filepath); 120 return NULL; 121 } 122 if (fstat(fd, &sb) == -1) { 123 _rtld_error("Cannot fstat \"%s\"", filepath); 124 close(fd); 125 return NULL; 126 } 127 for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) { 128 if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) { 129 close(fd); 130 break; 131 } 132 } 133 } 134 135 if (obj == NULL) { /* First use of this object, so we must map it in */ 136 obj = _rtld_map_object(filepath, fd, &sb); 137 (void)close(fd); 138 if (obj == NULL) { 139 free(filepath); 140 return NULL; 141 } 142 obj->path = filepath; 143 _rtld_digest_dynamic(obj); 144 145 *_rtld_objtail = obj; 146 _rtld_objtail = &obj->next; 147 #ifdef RTLD_LOADER 148 _rtld_linkmap_add(obj); /* for GDB */ 149 #endif 150 if (dodebug) { 151 dbg((" %p .. %p: %s", obj->mapbase, 152 obj->mapbase + obj->mapsize - 1, obj->path)); 153 if (obj->textrel) 154 dbg((" WARNING: %s has impure text", 155 obj->path)); 156 } 157 } else 158 free(filepath); 159 160 ++obj->refcount; 161 if ((mode & RTLD_GLOBAL) && 162 _rtld_objlist_find(&_rtld_list_global, obj) == NULL) 163 _rtld_objlist_add(&_rtld_list_global, obj); 164 return obj; 165 } 166 167 static bool 168 _rtld_load_by_name(name, obj, needed, mode, dodebug) 169 const char *name; 170 Obj_Entry *obj; 171 Needed_Entry **needed; 172 int mode; 173 bool dodebug; 174 { 175 Library_Xform *x = _rtld_xforms; 176 Obj_Entry *o = NULL; 177 size_t i, j; 178 char *libpath; 179 bool got = false; 180 union { 181 int i; 182 char s[16]; 183 } val; 184 185 if (dodebug) 186 dbg(("load by name %s %p", name, x)); 187 for (; x; x = x->next) { 188 if (strcmp(x->name, name) != 0) 189 continue; 190 191 i = sizeof(val); 192 193 if (sysctl(x->ctl, x->ctlmax, &val, &i, NULL, 0) == -1) { 194 xwarnx("sysctl"); 195 break; 196 } 197 198 switch (x->ctltype[x->ctlmax - 1]) { 199 case CTLTYPE_INT: 200 xsnprintf(val.s, sizeof(val.s), "%d", val.i); 201 break; 202 case CTLTYPE_STRING: 203 break; 204 default: 205 xwarnx("unsupported sysctl type %d", 206 x->ctltype[x->ctlmax - 1]); 207 break; 208 } 209 210 if (dodebug) 211 dbg(("sysctl returns %s", val.s)); 212 213 for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL; 214 i++) { 215 if (dodebug) 216 dbg(("entry %ld", (unsigned long)i)); 217 if (strcmp(x->entry[i].value, val.s) == 0) 218 break; 219 } 220 221 if (i == RTLD_MAX_ENTRY) { 222 xwarnx("sysctl value %s not found for lib%s", 223 val.s, name); 224 break; 225 } 226 /* XXX: This can mess up debuggers, cause we lie about 227 * what we loaded in the needed objects */ 228 for (j = 0; j < RTLD_MAX_LIBRARY && 229 x->entry[i].library[j] != NULL; j++) { 230 libpath = _rtld_find_library( 231 x->entry[i].library[j], obj); 232 if (libpath == NULL) { 233 xwarnx("could not load %s for %s", 234 x->entry[i].library[j], name); 235 continue; 236 } 237 o = _rtld_load_object(libpath, mode, true); 238 if (o == NULL) 239 continue; 240 got = true; 241 if (j == 0) 242 (*needed)->obj = o; 243 else { 244 /* make a new one and put it in the chain */ 245 Needed_Entry *ne = xmalloc(sizeof(*ne)); 246 ne->name = (*needed)->name; 247 ne->obj = o; 248 ne->next = (*needed)->next; 249 (*needed)->next = ne; 250 *needed = ne; 251 } 252 253 } 254 255 } 256 257 if (got) 258 return true; 259 260 libpath = _rtld_find_library(name, obj); 261 if (libpath == NULL) 262 return false; 263 return ((*needed)->obj = _rtld_load_object(libpath, mode, true)) != NULL; 264 } 265 266 267 /* 268 * Given a shared object, traverse its list of needed objects, and load 269 * each of them. Returns 0 on success. Generates an error message and 270 * returns -1 on failure. 271 */ 272 int 273 _rtld_load_needed_objects(first, mode, dodebug) 274 Obj_Entry *first; 275 int mode; 276 bool dodebug; 277 { 278 Obj_Entry *obj; 279 int status = 0; 280 281 for (obj = first; obj != NULL; obj = obj->next) { 282 Needed_Entry *needed; 283 284 for (needed = obj->needed; needed != NULL; 285 needed = needed->next) { 286 const char *name = obj->strtab + needed->name; 287 if (!_rtld_load_by_name(name, obj, &needed, mode, 288 dodebug)) 289 status = -1; /* FIXME - cleanup */ 290 #ifdef RTLD_LOADER 291 if (status == -1) 292 return status; 293 #endif 294 } 295 } 296 297 return status; 298 } 299 300 #ifdef RTLD_LOADER 301 int 302 _rtld_preload(preload_path, dodebug) 303 const char *preload_path; 304 bool dodebug; 305 { 306 const char *path; 307 char *cp, *buf; 308 int status = 0; 309 310 if (preload_path != NULL) { 311 cp = buf = xstrdup(preload_path); 312 while ((path = strsep(&cp, " :")) != NULL && status == 0) { 313 if (_rtld_load_object(xstrdup(path), RTLD_GLOBAL, 314 dodebug) == NULL) 315 status = -1; 316 else if (dodebug) 317 dbg((" preloaded \"%s\"", path)); 318 } 319 free(buf); 320 } 321 322 return (status); 323 } 324 #endif 325