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