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