1 /* $OpenBSD: dlfcn.c,v 1.97 2017/05/08 02:34:01 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #define _DYN_LOADER 30 31 #include <sys/types.h> 32 #include <nlist.h> 33 #include <link.h> 34 #include <dlfcn.h> 35 #include <unistd.h> 36 37 #include "syscall.h" 38 #include "archdep.h" 39 #include "resolve.h" 40 #include "sod.h" 41 42 int _dl_errno; 43 static int _dl_tracelib; 44 45 static int _dl_real_close(void *handle); 46 static lock_cb *_dl_thread_fnc = NULL; 47 static elf_object_t *obj_from_addr(const void *addr); 48 49 void * 50 dlopen(const char *libname, int flags) 51 { 52 elf_object_t *object; 53 lock_cb *cb; 54 int failed = 0; 55 int obj_flags; 56 57 if (flags & ~(RTLD_TRACE|RTLD_LAZY|RTLD_NOW|RTLD_GLOBAL)) { 58 _dl_errno = DL_INVALID_MODE; 59 return NULL; 60 } 61 62 if (libname == NULL) 63 return RTLD_DEFAULT; 64 65 if ((flags & RTLD_TRACE) == RTLD_TRACE) { 66 _dl_traceld = "true"; 67 _dl_tracelib = 1; 68 } 69 70 DL_DEB(("dlopen: loading: %s\n", libname)); 71 72 cb = _dl_thread_kern_stop(); 73 74 if (_dl_debug_map && _dl_debug_map->r_brk) { 75 _dl_debug_map->r_state = RT_ADD; 76 (*((void (*)(void))_dl_debug_map->r_brk))(); 77 } 78 79 _dl_loading_object = NULL; 80 81 obj_flags = (flags & RTLD_NOW ? DF_1_NOW : 0) 82 | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0); 83 object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, obj_flags); 84 if (object == 0) { 85 DL_DEB(("dlopen: failed to open %s\n", libname)); 86 failed = 1; 87 goto loaded; 88 } 89 90 _dl_link_dlopen(object); 91 92 if (OBJECT_REF_CNT(object) > 1) { 93 /* if opened but grpsym_list has not been created */ 94 if (OBJECT_DLREF_CNT(object) == 1) { 95 /* add first object manually */ 96 _dl_link_grpsym(object, 1); 97 _dl_cache_grpsym_list(object); 98 } 99 goto loaded; 100 } 101 102 /* this add_object should not be here, XXX */ 103 _dl_add_object(object); 104 105 DL_DEB(("head [%s]\n", object->load_name )); 106 107 if ((failed = _dl_load_dep_libs(object, obj_flags, 0)) == 1) { 108 _dl_real_close(object); 109 object = NULL; 110 _dl_errno = DL_CANT_LOAD_OBJ; 111 } else { 112 int err; 113 DL_DEB(("tail %s\n", object->load_name )); 114 if (_dl_traceld) { 115 _dl_show_objects(); 116 _dl_unload_shlib(object); 117 _dl_exit(0); 118 } 119 err = _dl_rtld(object); 120 if (err != 0) { 121 _dl_real_close(object); 122 _dl_errno = DL_CANT_LOAD_OBJ; 123 object = NULL; 124 failed = 1; 125 } else { 126 _dl_call_init(object); 127 } 128 } 129 130 loaded: 131 _dl_loading_object = NULL; 132 133 if (_dl_debug_map && _dl_debug_map->r_brk) { 134 _dl_debug_map->r_state = RT_CONSISTENT; 135 (*((void (*)(void))_dl_debug_map->r_brk))(); 136 } 137 138 _dl_thread_kern_go(cb); 139 140 DL_DEB(("dlopen: %s: done (%s).\n", libname, 141 failed ? "failed" : "success")); 142 143 return((void *)object); 144 } 145 146 void * 147 dlsym(void *handle, const char *name) 148 { 149 elf_object_t *object; 150 elf_object_t *dynobj; 151 const elf_object_t *pobj; 152 char *retval; 153 const Elf_Sym *sym = NULL; 154 int flags; 155 156 if (handle == NULL || handle == RTLD_NEXT || 157 handle == RTLD_SELF || handle == RTLD_DEFAULT) { 158 void *retaddr; 159 160 retaddr = __builtin_return_address(0); /* __GNUC__ only */ 161 162 if ((object = obj_from_addr(retaddr)) == NULL) { 163 _dl_errno = DL_CANT_FIND_OBJ; 164 return(0); 165 } 166 167 if (handle == RTLD_NEXT) 168 flags = SYM_SEARCH_NEXT|SYM_PLT; 169 else if (handle == RTLD_SELF) 170 flags = SYM_SEARCH_SELF|SYM_PLT; 171 else if (handle == RTLD_DEFAULT) 172 flags = SYM_SEARCH_ALL|SYM_PLT; 173 else 174 flags = SYM_DLSYM|SYM_PLT; 175 176 } else { 177 object = (elf_object_t *)handle; 178 flags = SYM_DLSYM|SYM_PLT; 179 180 dynobj = _dl_objects; 181 while (dynobj && dynobj != object) 182 dynobj = dynobj->next; 183 184 if (!dynobj || object != dynobj) { 185 _dl_errno = DL_INVALID_HANDLE; 186 return(0); 187 } 188 } 189 190 retval = (void *)_dl_find_symbol(name, &sym, 191 flags|SYM_NOWARNNOTFOUND, NULL, object, &pobj); 192 193 if (sym != NULL) { 194 retval += sym->st_value; 195 #ifdef __hppa__ 196 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) 197 retval = (void *)_dl_md_plabel((Elf_Addr)retval, 198 pobj->dyn.pltgot); 199 #endif 200 DL_DEB(("dlsym: %s in %s: %p\n", 201 name, object->load_name, retval)); 202 } else 203 _dl_errno = DL_NO_SYMBOL; 204 return (retval); 205 } 206 207 int 208 dlctl(void *handle, int command, void *data) 209 { 210 int retval; 211 212 switch (command) { 213 case DL_SETTHREADLCK: 214 DL_DEB(("dlctl: _dl_thread_fnc set to %p\n", data)); 215 _dl_thread_fnc = data; 216 retval = 0; 217 break; 218 case DL_SETBINDLCK: 219 /* made superfluous by kbind */ 220 retval = 0; 221 break; 222 case 0x20: 223 _dl_show_objects(); 224 retval = 0; 225 break; 226 case 0x21: 227 { 228 struct dep_node *n, *m; 229 elf_object_t *obj; 230 _dl_printf("Load Groups:\n"); 231 232 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 233 obj = n->data; 234 _dl_printf("%s\n", obj->load_name); 235 236 _dl_printf(" children\n"); 237 TAILQ_FOREACH(m, &obj->child_list, next_sib) 238 _dl_printf("\t[%s]\n", m->data->load_name); 239 240 _dl_printf(" grpref\n"); 241 TAILQ_FOREACH(m, &obj->grpref_list, next_sib) 242 _dl_printf("\t[%s]\n", m->data->load_name); 243 _dl_printf("\n"); 244 } 245 retval = 0; 246 break; 247 } 248 default: 249 _dl_errno = DL_INVALID_CTL; 250 retval = -1; 251 break; 252 } 253 return (retval); 254 } 255 __strong_alias(_dlctl,dlctl); 256 257 int 258 dlclose(void *handle) 259 { 260 lock_cb *cb; 261 int retval; 262 263 if (handle == RTLD_DEFAULT) 264 return 0; 265 266 cb = _dl_thread_kern_stop(); 267 268 if (_dl_debug_map && _dl_debug_map->r_brk) { 269 _dl_debug_map->r_state = RT_DELETE; 270 (*((void (*)(void))_dl_debug_map->r_brk))(); 271 } 272 273 retval = _dl_real_close(handle); 274 275 if (_dl_debug_map && _dl_debug_map->r_brk) { 276 _dl_debug_map->r_state = RT_CONSISTENT; 277 (*((void (*)(void))_dl_debug_map->r_brk))(); 278 } 279 _dl_thread_kern_go(cb); 280 return (retval); 281 } 282 283 int 284 _dl_real_close(void *handle) 285 { 286 elf_object_t *object; 287 elf_object_t *dynobj; 288 289 object = (elf_object_t *)handle; 290 291 dynobj = _dl_objects; 292 while (dynobj && dynobj != object) 293 dynobj = dynobj->next; 294 295 if (!dynobj || object != dynobj) { 296 _dl_errno = DL_INVALID_HANDLE; 297 return (1); 298 } 299 300 if (object->opencount == 0) { 301 _dl_errno = DL_INVALID_HANDLE; 302 return (1); 303 } 304 305 object->opencount--; 306 _dl_notify_unload_shlib(object); 307 _dl_run_all_dtors(); 308 _dl_unload_shlib(object); 309 _dl_cleanup_objects(); 310 return (0); 311 } 312 313 314 /* 315 * Return a character string describing the last dl... error occurred. 316 */ 317 char * 318 dlerror(void) 319 { 320 char *errmsg; 321 322 switch (_dl_errno) { 323 case 0: /* NO ERROR */ 324 errmsg = NULL; 325 break; 326 case DL_NOT_FOUND: 327 errmsg = "File not found"; 328 break; 329 case DL_CANT_OPEN: 330 errmsg = "Can't open file"; 331 break; 332 case DL_NOT_ELF: 333 errmsg = "File not an ELF object"; 334 break; 335 case DL_CANT_OPEN_REF: 336 errmsg = "Can't open referenced object"; 337 break; 338 case DL_CANT_MMAP: 339 errmsg = "Can't map ELF object"; 340 break; 341 case DL_INVALID_HANDLE: 342 errmsg = "Invalid handle"; 343 break; 344 case DL_NO_SYMBOL: 345 errmsg = "Unable to resolve symbol"; 346 break; 347 case DL_INVALID_CTL: 348 errmsg = "Invalid dlctl() command"; 349 break; 350 case DL_NO_OBJECT: 351 errmsg = "No shared object contains address"; 352 break; 353 case DL_CANT_FIND_OBJ: 354 errmsg = "Cannot determine caller's shared object"; 355 break; 356 case DL_CANT_LOAD_OBJ: 357 errmsg = "Cannot load specified object"; 358 break; 359 case DL_INVALID_MODE: 360 errmsg = "Invalid mode"; 361 break; 362 default: 363 errmsg = "Unknown error"; 364 } 365 366 _dl_errno = 0; 367 return (errmsg); 368 } 369 370 static void 371 _dl_tracefmt(int fd, elf_object_t *object, const char *fmt1, const char *fmt2, 372 const char *objtypename) 373 { 374 const char *fmt; 375 int i; 376 377 fmt = object->sod.sod_library ? fmt1 : fmt2; 378 379 for (i = 0; fmt[i]; i++) { 380 if (fmt[i] != '%' && fmt[i] != '\\') { 381 _dl_fdprintf(fd, "%c", fmt[i]); 382 continue; 383 } 384 if (fmt[i] == '%') { 385 i++; 386 switch (fmt[i]) { 387 case '\0': 388 return; 389 case '%': 390 _dl_fdprintf(fd, "%c", '%'); 391 break; 392 case 'A': 393 _dl_fdprintf(fd, "%s", _dl_traceprog ? 394 _dl_traceprog : ""); 395 break; 396 case 'a': 397 _dl_fdprintf(fd, "%s", __progname); 398 break; 399 case 'e': 400 _dl_fdprintf(fd, "%lX", 401 (void *)(object->load_base + 402 object->load_size)); 403 break; 404 case 'g': 405 _dl_fdprintf(fd, "%d", object->grprefcount); 406 break; 407 case 'm': 408 _dl_fdprintf(fd, "%d", object->sod.sod_major); 409 break; 410 case 'n': 411 _dl_fdprintf(fd, "%d", object->sod.sod_minor); 412 break; 413 case 'O': 414 _dl_fdprintf(fd, "%d", object->opencount); 415 break; 416 case 'o': 417 _dl_fdprintf(fd, "%s", object->sod.sod_name); 418 break; 419 case 'p': 420 _dl_fdprintf(fd, "%s", object->load_name); 421 break; 422 case 'r': 423 _dl_fdprintf(fd, "%d", object->refcount); 424 break; 425 case 't': 426 _dl_fdprintf(fd, "%s", objtypename); 427 break; 428 case 'x': 429 _dl_fdprintf(fd, "%lX", object->load_base); 430 break; 431 } 432 } 433 if (fmt[i] == '\\') { 434 i++; 435 switch (fmt[i]) { 436 case '\0': 437 return; 438 case 'n': 439 _dl_fdprintf(fd, "%c", '\n'); 440 break; 441 case 'r': 442 _dl_fdprintf(fd, "%c", '\r'); 443 break; 444 case 't': 445 _dl_fdprintf(fd, "%c", '\t'); 446 break; 447 default: 448 _dl_fdprintf(fd, "%c", fmt[i]); 449 break; 450 } 451 } 452 } 453 } 454 455 void 456 _dl_show_objects(void) 457 { 458 elf_object_t *object; 459 char *objtypename; 460 int outputfd; 461 char *pad; 462 const char *fmt1, *fmt2; 463 464 object = _dl_objects; 465 if (_dl_traceld) 466 outputfd = STDOUT_FILENO; 467 else 468 outputfd = STDERR_FILENO; 469 470 if (sizeof(long) == 8) 471 pad = " "; 472 else 473 pad = ""; 474 475 fmt1 = _dl_tracefmt1 ? _dl_tracefmt1 : 476 "\t%x %e %t %O %r %g %p\n"; 477 fmt2 = _dl_tracefmt2 ? _dl_tracefmt2 : 478 "\t%x %e %t %O %r %g %p\n"; 479 480 if (_dl_tracefmt1 == NULL && _dl_tracefmt2 == NULL) 481 _dl_fdprintf(outputfd, "\tStart %s End %s Type Open Ref GrpRef Name\n", 482 pad, pad); 483 484 if (_dl_tracelib) { 485 for (; object != NULL; object = object->next) 486 if (object->obj_type == OBJTYPE_LDR) { 487 object = object->next; 488 break; 489 } 490 } 491 492 for (; object != NULL; object = object->next) { 493 switch (object->obj_type) { 494 case OBJTYPE_LDR: 495 objtypename = "rtld"; 496 break; 497 case OBJTYPE_EXE: 498 objtypename = "exe "; 499 break; 500 case OBJTYPE_LIB: 501 objtypename = "rlib"; 502 break; 503 case OBJTYPE_DLO: 504 objtypename = "dlib"; 505 break; 506 default: 507 objtypename = "????"; 508 break; 509 } 510 _dl_tracefmt(outputfd, object, fmt1, fmt2, objtypename); 511 } 512 513 if (_dl_symcachestat_lookups != 0) 514 DL_DEB(("symcache lookups %d hits %d ratio %d% hits\n", 515 _dl_symcachestat_lookups, _dl_symcachestat_hits, 516 (_dl_symcachestat_hits * 100) / 517 _dl_symcachestat_lookups)); 518 } 519 520 lock_cb * 521 _dl_thread_kern_stop(void) 522 { 523 lock_cb *cb = _dl_thread_fnc; 524 525 if (cb != NULL) 526 (*cb)(0); 527 return cb; 528 } 529 530 void 531 _dl_thread_kern_go(lock_cb *cb) 532 { 533 if (cb != NULL) 534 (*cb)(1); 535 } 536 537 int 538 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *data), 539 void *data) 540 { 541 elf_object_t *object; 542 struct dl_phdr_info info; 543 int retval = -1; 544 545 for (object = _dl_objects; object != NULL; object = object->next) { 546 if (object->phdrp == NULL) 547 continue; 548 549 info.dlpi_addr = object->obj_base; 550 info.dlpi_name = object->load_name; 551 info.dlpi_phdr = object->phdrp; 552 info.dlpi_phnum = object->phdrc; 553 retval = callback(&info, sizeof (struct dl_phdr_info), data); 554 if (retval) 555 break; 556 } 557 558 return retval; 559 } 560 561 static elf_object_t * 562 obj_from_addr(const void *addr) 563 { 564 elf_object_t *dynobj; 565 Elf_Phdr *phdrp; 566 int phdrc; 567 Elf_Addr start; 568 int i; 569 570 for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) { 571 if (dynobj->phdrp == NULL) 572 continue; 573 574 phdrp = dynobj->phdrp; 575 phdrc = dynobj->phdrc; 576 577 for (i = 0; i < phdrc; i++, phdrp++) { 578 if (phdrp->p_type == PT_LOAD) { 579 start = dynobj->obj_base + phdrp->p_vaddr; 580 if ((Elf_Addr)addr >= start && 581 (Elf_Addr)addr < start + phdrp->p_memsz) 582 return dynobj; 583 } 584 } 585 } 586 587 return NULL; 588 } 589 590 int 591 dladdr(const void *addr, Dl_info *info) 592 { 593 const elf_object_t *object; 594 const Elf_Sym *sym; 595 void *symbol_addr; 596 u_int32_t symoffset; 597 598 object = obj_from_addr(addr); 599 600 if (object == NULL) { 601 _dl_errno = DL_NO_OBJECT; 602 return 0; 603 } 604 605 info->dli_fname = (char *)object->load_name; 606 info->dli_fbase = (void *)object->load_base; 607 info->dli_sname = NULL; 608 info->dli_saddr = NULL; 609 610 /* 611 * Walk the symbol list looking for the symbol whose address is 612 * closest to the address sent in. 613 */ 614 for (symoffset = 0; symoffset < object->nchains; symoffset++) { 615 sym = object->dyn.symtab + symoffset; 616 617 /* 618 * For skip the symbol if st_shndx is either SHN_UNDEF or 619 * SHN_COMMON. 620 */ 621 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON) 622 continue; 623 624 /* 625 * If the symbol is greater than the specified address, or if 626 * it is further away from addr than the current nearest 627 * symbol, then reject it. 628 */ 629 symbol_addr = (void *)(object->obj_base + sym->st_value); 630 if (symbol_addr > addr || symbol_addr < info->dli_saddr) 631 continue; 632 633 /* Update our idea of the nearest symbol. */ 634 info->dli_sname = object->dyn.strtab + sym->st_name; 635 info->dli_saddr = symbol_addr; 636 637 /* Exact match? */ 638 if (info->dli_saddr == addr) 639 break; 640 } 641 642 return 1; 643 } 644