resolve.c revision 1.84
1/* $OpenBSD: resolve.c,v 1.84 2018/11/15 21:25:44 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 33#include <limits.h> 34#include <nlist.h> 35#include <link.h> 36#include "syscall.h" 37#include "archdep.h" 38#include "path.h" 39#include "resolve.h" 40 41/* substitution types */ 42typedef enum { 43 SUBST_UNKNOWN, SUBST_ORIGIN, SUBST_OSNAME, SUBST_OSREL, SUBST_PLATFORM 44} SUBST_TYPES; 45 46struct symlookup { 47 const char *sl_name; 48 const elf_object_t *sl_obj_out; 49 const Elf_Sym *sl_sym_out; 50 const elf_object_t *sl_weak_obj_out; 51 const Elf_Sym *sl_weak_sym_out; 52 unsigned long sl_elf_hash; 53 int sl_flags; 54}; 55 56elf_object_t *_dl_objects; 57elf_object_t *_dl_last_object; 58elf_object_t *_dl_loading_object; 59 60/* 61 * Add a new dynamic object to the object list. 62 */ 63void 64_dl_add_object(elf_object_t *object) 65{ 66 /* 67 * If a .so is marked nodelete, then the entire load group that it's 68 * in needs to be kept around forever, so add a reference there. 69 * XXX It would be better if we tracked inter-object dependencies 70 * from relocations and didn't leave dangling pointers when a load 71 * group was partially unloaded. That would render this unnecessary. 72 */ 73 if (object->obj_flags & DF_1_NODELETE && 74 (object->load_object->status & STAT_NODELETE) == 0) { 75 DL_DEB(("objname %s is nodelete\n", object->load_name)); 76 object->load_object->opencount++; 77 object->load_object->status |= STAT_NODELETE; 78 } 79 80 /* 81 * if this is a new object, prev will be NULL 82 * != NULL if an object already in the list 83 * prev == NULL for the first item in the list, but that will 84 * be the executable. 85 */ 86 if (object->prev != NULL) 87 return; 88 89 if (_dl_objects == NULL) { /* First object ? */ 90 _dl_last_object = _dl_objects = object; 91 } else { 92 _dl_last_object->next = object; 93 object->prev = _dl_last_object; 94 _dl_last_object = object; 95 } 96} 97 98/* 99 * Identify substitution sequence name. 100 */ 101static int 102_dl_subst_name(const char *name, size_t siz) { 103 switch (siz) { 104 case 5: 105 if (_dl_strncmp(name, "OSREL", 5) == 0) 106 return SUBST_OSREL; 107 break; 108 case 6: 109 if (_dl_strncmp(name, "ORIGIN", 6) == 0) 110 return SUBST_ORIGIN; 111 if (_dl_strncmp(name, "OSNAME", 6) == 0) 112 return SUBST_OSNAME; 113 break; 114 case 8: 115 if (_dl_strncmp(name, "PLATFORM", 8) == 0) 116 return SUBST_PLATFORM; 117 break; 118 } 119 120 return (SUBST_UNKNOWN); 121} 122 123/* 124 * Perform $ORIGIN substitutions on path 125 */ 126static void 127_dl_origin_subst_path(elf_object_t *object, const char *origin_path, 128 char **path) 129{ 130 char tmp_path[PATH_MAX]; 131 char *new_path, *tp; 132 const char *pp, *name, *value; 133 static struct utsname uts; 134 size_t value_len; 135 int skip_brace; 136 137 if (uts.sysname[0] == '\0') { 138 if (_dl_uname(&uts) != 0) 139 return; 140 } 141 142 tp = tmp_path; 143 pp = *path; 144 145 while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) { 146 147 /* copy over chars up to but not including $ */ 148 while (*pp != '\0' && *pp != '$' && 149 (tp - tmp_path) < sizeof(tmp_path)) 150 *tp++ = *pp++; 151 152 /* substitution sequence detected */ 153 if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) { 154 pp++; 155 156 if ((skip_brace = (*pp == '{'))) 157 pp++; 158 159 /* skip over name */ 160 name = pp; 161 while (_dl_isalnum((unsigned char)*pp) || *pp == '_') 162 pp++; 163 164 switch (_dl_subst_name(name, pp - name)) { 165 case SUBST_ORIGIN: 166 value = origin_path; 167 break; 168 case SUBST_OSNAME: 169 value = uts.sysname; 170 break; 171 case SUBST_OSREL: 172 value = uts.release; 173 break; 174 case SUBST_PLATFORM: 175 value = uts.machine; 176 break; 177 default: 178 value = ""; 179 } 180 181 value_len = _dl_strlen(value); 182 if (value_len >= sizeof(tmp_path) - (tp - tmp_path)) 183 return; 184 185 _dl_bcopy(value, tp, value_len); 186 tp += value_len; 187 188 if (skip_brace && *pp == '}') 189 pp++; 190 } 191 } 192 193 /* no substitution made if result exceeds sizeof(tmp_path) */ 194 if (tp - tmp_path >= sizeof(tmp_path)) 195 return; 196 197 /* NULL terminate tmp_path */ 198 *tp = '\0'; 199 200 if (_dl_strcmp(tmp_path, *path) == 0) 201 return; 202 203 new_path = _dl_strdup(tmp_path); 204 if (new_path == NULL) 205 return; 206 207 DL_DEB(("orig_path %s\n", *path)); 208 DL_DEB(("new_path %s\n", new_path)); 209 210 _dl_free(*path); 211 *path = new_path; 212} 213 214/* 215 * Determine origin_path from object load_name. The origin_path argument 216 * must refer to a buffer capable of storing at least PATH_MAX characters. 217 * Returns 0 on success. 218 */ 219static int 220_dl_origin_path(elf_object_t *object, char *origin_path) 221{ 222 const char *dirname_path = _dl_dirname(object->load_name); 223 224 if (dirname_path == NULL) 225 return -1; 226 227 if (_dl_realpath(dirname_path, origin_path) == NULL) 228 return -1; 229 230 return 0; 231} 232 233/* 234 * Perform $ORIGIN substitutions on runpath and rpath 235 */ 236static void 237_dl_origin_subst(elf_object_t *object) 238{ 239 char origin_path[PATH_MAX]; 240 char **pp; 241 242 if (_dl_origin_path(object, origin_path) != 0) 243 return; 244 245 /* perform path substitutions on each segment of runpath and rpath */ 246 if (object->runpath != NULL) { 247 for (pp = object->runpath; *pp != NULL; pp++) 248 _dl_origin_subst_path(object, origin_path, pp); 249 } 250 if (object->rpath != NULL) { 251 for (pp = object->rpath; *pp != NULL; pp++) 252 _dl_origin_subst_path(object, origin_path, pp); 253 } 254} 255 256/* 257 * Initialize a new dynamic object. 258 */ 259elf_object_t * 260_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, 261 int phdrc, const int objtype, const long lbase, const long obase) 262{ 263 elf_object_t *object; 264 265#if 0 266 _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", 267 objname, dynp, objtype, lbase, obase); 268#endif 269 object = _dl_calloc(1, sizeof(elf_object_t)); 270 if (object == NULL) 271 _dl_oom(); 272 object->prev = object->next = NULL; 273 274 object->load_dyn = dynp; 275 while (dynp->d_tag != DT_NULL) { 276 if (dynp->d_tag < DT_NUM) 277 object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val; 278 else if (dynp->d_tag >= DT_LOPROC && 279 dynp->d_tag < DT_LOPROC + DT_PROCNUM) 280 object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = 281 dynp->d_un.d_val; 282 if (dynp->d_tag == DT_TEXTREL) 283 object->dyn.textrel = 1; 284 if (dynp->d_tag == DT_SYMBOLIC) 285 object->dyn.symbolic = 1; 286 if (dynp->d_tag == DT_BIND_NOW) 287 object->obj_flags |= DF_1_NOW; 288 if (dynp->d_tag == DT_FLAGS_1) 289 object->obj_flags |= dynp->d_un.d_val; 290 if (dynp->d_tag == DT_FLAGS) { 291 object->dyn.flags |= dynp->d_un.d_val; 292 if (dynp->d_un.d_val & DF_SYMBOLIC) 293 object->dyn.symbolic = 1; 294 if (dynp->d_un.d_val & DF_TEXTREL) 295 object->dyn.textrel = 1; 296 if (dynp->d_un.d_val & DF_ORIGIN) 297 object->obj_flags |= DF_1_ORIGIN; 298 if (dynp->d_un.d_val & DF_BIND_NOW) 299 object->obj_flags |= DF_1_NOW; 300 } 301 if (dynp->d_tag == DT_RELACOUNT) 302 object->relacount = dynp->d_un.d_val; 303 if (dynp->d_tag == DT_RELCOUNT) 304 object->relcount = dynp->d_un.d_val; 305 dynp++; 306 } 307 DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags )); 308 object->obj_type = objtype; 309 310 if (_dl_loading_object == NULL) { 311 /* 312 * no loading object, object is the loading object, 313 * as it is either executable, or dlopened() 314 */ 315 _dl_loading_object = object; 316 } 317 318 if ((object->obj_flags & DF_1_NOOPEN) != 0 && 319 _dl_loading_object->obj_type == OBJTYPE_DLO && 320 !_dl_traceld) { 321 _dl_free(object); 322 _dl_errno = DL_CANT_LOAD_OBJ; 323 return(NULL); 324 } 325 326 /* 327 * Now relocate all pointer to dynamic info, but only 328 * the ones which have pointer values. 329 */ 330 if (object->Dyn.info[DT_PLTGOT]) 331 object->Dyn.info[DT_PLTGOT] += obase; 332 if (object->Dyn.info[DT_HASH]) 333 object->Dyn.info[DT_HASH] += obase; 334 if (object->Dyn.info[DT_STRTAB]) 335 object->Dyn.info[DT_STRTAB] += obase; 336 if (object->Dyn.info[DT_SYMTAB]) 337 object->Dyn.info[DT_SYMTAB] += obase; 338 if (object->Dyn.info[DT_RELA]) 339 object->Dyn.info[DT_RELA] += obase; 340 if (object->Dyn.info[DT_SONAME]) 341 object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB]; 342 if (object->Dyn.info[DT_RPATH]) 343 object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB]; 344 if (object->Dyn.info[DT_RUNPATH]) 345 object->Dyn.info[DT_RUNPATH] += object->Dyn.info[DT_STRTAB]; 346 if (object->Dyn.info[DT_REL]) 347 object->Dyn.info[DT_REL] += obase; 348 if (object->Dyn.info[DT_INIT]) 349 object->Dyn.info[DT_INIT] += obase; 350 if (object->Dyn.info[DT_FINI]) 351 object->Dyn.info[DT_FINI] += obase; 352 if (object->Dyn.info[DT_JMPREL]) 353 object->Dyn.info[DT_JMPREL] += obase; 354 if (object->Dyn.info[DT_INIT_ARRAY]) 355 object->Dyn.info[DT_INIT_ARRAY] += obase; 356 if (object->Dyn.info[DT_FINI_ARRAY]) 357 object->Dyn.info[DT_FINI_ARRAY] += obase; 358 if (object->Dyn.info[DT_PREINIT_ARRAY]) 359 object->Dyn.info[DT_PREINIT_ARRAY] += obase; 360 361 if (object->Dyn.info[DT_HASH] != 0) { 362 Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH]; 363 364 object->nbuckets = hashtab[0]; 365 object->nchains = hashtab[1]; 366 object->buckets = hashtab + 2; 367 object->chains = object->buckets + object->nbuckets; 368 } 369 370 object->phdrp = phdrp; 371 object->phdrc = phdrc; 372 object->load_base = lbase; 373 object->obj_base = obase; 374 object->load_name = _dl_strdup(objname); 375 if (object->load_name == NULL) 376 _dl_oom(); 377 object->load_object = _dl_loading_object; 378 if (object->load_object == object) 379 DL_DEB(("head %s\n", object->load_name)); 380 DL_DEB(("obj %s has %s as head\n", object->load_name, 381 _dl_loading_object->load_name )); 382 object->refcount = 0; 383 TAILQ_INIT(&object->child_list); 384 object->opencount = 0; /* # dlopen() & exe */ 385 object->grprefcount = 0; 386 /* default dev, inode for dlopen-able objects. */ 387 object->dev = 0; 388 object->inode = 0; 389 object->grpsym_gen = 0; 390 TAILQ_INIT(&object->grpsym_list); 391 TAILQ_INIT(&object->grpref_list); 392 393 if (object->dyn.runpath) 394 object->runpath = _dl_split_path(object->dyn.runpath); 395 /* 396 * DT_RPATH is ignored if DT_RUNPATH is present...except in 397 * the exe, whose DT_RPATH is a fallback for libs that don't 398 * use DT_RUNPATH 399 */ 400 if (object->dyn.rpath && (object->runpath == NULL || 401 objtype == OBJTYPE_EXE)) 402 object->rpath = _dl_split_path(object->dyn.rpath); 403 if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust) 404 _dl_origin_subst(object); 405 406 _dl_trace_object_setup(object); 407 408 return (object); 409} 410 411static void 412_dl_tailq_free(struct dep_node *n) 413{ 414 struct dep_node *next; 415 416 while (n != NULL) { 417 next = TAILQ_NEXT(n, next_sib); 418 _dl_free(n); 419 n = next; 420 } 421} 422 423static elf_object_t *free_objects; 424 425void 426_dl_cleanup_objects() 427{ 428 elf_object_t *nobj, *head; 429 struct dep_node *n, *next; 430 431 n = TAILQ_FIRST(&_dlopened_child_list); 432 while (n != NULL) { 433 next = TAILQ_NEXT(n, next_sib); 434 if (OBJECT_DLREF_CNT(n->data) == 0) { 435 TAILQ_REMOVE(&_dlopened_child_list, n, next_sib); 436 _dl_free(n); 437 } 438 n = next; 439 } 440 441 head = free_objects; 442 free_objects = NULL; 443 while (head != NULL) { 444 _dl_free(head->load_name); 445 _dl_free((char *)head->sod.sod_name); 446 _dl_free_path(head->runpath); 447 _dl_free_path(head->rpath); 448 _dl_tailq_free(TAILQ_FIRST(&head->grpsym_list)); 449 _dl_tailq_free(TAILQ_FIRST(&head->child_list)); 450 _dl_tailq_free(TAILQ_FIRST(&head->grpref_list)); 451 nobj = head->next; 452 _dl_free(head); 453 head = nobj; 454 } 455} 456 457void 458_dl_remove_object(elf_object_t *object) 459{ 460 object->prev->next = object->next; 461 if (object->next) 462 object->next->prev = object->prev; 463 464 if (_dl_last_object == object) 465 _dl_last_object = object->prev; 466 467 object->next = free_objects; 468 free_objects = object; 469} 470 471/* 472 * mprotect a segment to the indicated protection. If 'addr' is non-zero, 473 * then it's the start address, else the value of 'start_sym' is the start. 474 * The value of 'end_sym' is the end address. The start is rounded down 475 * and the end is rounded up to page boundaries. Returns 'addr' or the 476 * address of the start symbol. 477 */ 478void * 479_dl_protect_segment(elf_object_t *object, Elf_Addr addr, 480 const char *start_sym, const char *end_sym, int prot) 481{ 482 const Elf_Sym *this; 483 Elf_Addr ooff, start, end; 484 485 if (addr == 0 && start_sym[2] == 'g' && 486 (addr = object->relro_addr) != 0) { 487 DL_DEB(("protect start RELRO = 0x%lx in %s\n", 488 addr, object->load_name)); 489 } 490 else if (addr == 0) { 491 this = NULL; 492 ooff = _dl_find_symbol(start_sym, &this, 493 SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL, 494 object, NULL); 495 /* If not found, nothing to do */ 496 if (this == NULL) { 497 DL_DEB(("protect start \"%s\" not found in %s\n", 498 start_sym, object->load_name)); 499 return (NULL); 500 } 501 addr = ooff + this->st_value; 502 DL_DEB(("protect start \"%s\" to %x = 0x%lx in %s\n", 503 start_sym, prot, addr, object->load_name)); 504 } 505 506 if (object->relro_addr != 0 && start_sym[2] == 'g') { 507 end = object->relro_addr + object->relro_size; 508 DL_DEB(("protect end RELRO = 0x%lx in %s\n", 509 end, object->load_name)); 510 } else { 511 this = NULL; 512 ooff = _dl_find_symbol(end_sym, &this, 513 SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL, 514 object, NULL); 515 if (this == NULL) { 516 DL_DEB(("protect end \"%s\" not found in %s\n", 517 end_sym, object->load_name)); 518 addr = 0; 519 } else { 520 end = ooff + this->st_value; 521 DL_DEB(("protect end \"%s\" = 0x%lx in %s\n", 522 end_sym, end, object->load_name)); 523 } 524 } 525 526 if (addr != 0 && addr < end) { 527 start = ELF_TRUNC(addr, _dl_pagesz); 528 end = ELF_ROUND(end, _dl_pagesz); 529 _dl_mprotect((void *)start, end - start, prot); 530 } 531 532 return ((void *)addr); 533} 534 535 536sym_cache *_dl_symcache; 537int _dl_symcachestat_hits; 538int _dl_symcachestat_lookups; 539 540 541Elf_Addr 542_dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx, 543 const Elf_Sym **this, int flags, const Elf_Sym *ref_sym, const elf_object_t **pobj) 544{ 545 Elf_Addr ret; 546 const Elf_Sym *sym; 547 const char *symn; 548 const elf_object_t *sobj; 549 550 _dl_symcachestat_lookups ++; 551 if (_dl_symcache != NULL && 552 symidx < req_obj->nchains && 553 _dl_symcache[symidx].obj != NULL && 554 _dl_symcache[symidx].sym != NULL && 555 _dl_symcache[symidx].flags == flags) { 556 557 _dl_symcachestat_hits++; 558 sobj = _dl_symcache[symidx].obj; 559 *this = _dl_symcache[symidx].sym; 560 if (pobj) 561 *pobj = sobj; 562 return sobj->obj_base; 563 } 564 565 sym = req_obj->dyn.symtab; 566 sym += symidx; 567 symn = req_obj->dyn.strtab + sym->st_name; 568 569 ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj); 570 571 if (pobj) 572 *pobj = sobj; 573 574 if (_dl_symcache != NULL && symidx < req_obj->nchains) { 575#if 0 576 DL_DEB(("cache miss %d %p %p, %p %p %s %s %d %d %s\n", 577 symidx, 578 _dl_symcache[symidx].sym, *this, 579 _dl_symcache[symidx].obj, sobj, sobj->load_name, 580 sobj->dyn.strtab + (*this)->st_name, 581 _dl_symcache[symidx].flags, flags, req_obj->load_name)); 582#endif 583 584 _dl_symcache[symidx].sym = *this; 585 _dl_symcache[symidx].obj = sobj; 586 _dl_symcache[symidx].flags = flags; 587 } 588 589 return ret; 590} 591 592static int 593_dl_find_symbol_obj(elf_object_t *obj, struct symlookup *sl) 594{ 595 const Elf_Sym *symt = obj->dyn.symtab; 596 const char *strt = obj->dyn.strtab; 597 long si; 598 const char *symn; 599 600 for (si = obj->buckets[sl->sl_elf_hash % obj->nbuckets]; 601 si != STN_UNDEF; si = obj->chains[si]) { 602 const Elf_Sym *sym = symt + si; 603 604 if (sym->st_value == 0) 605 continue; 606 607 if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE && 608 ELF_ST_TYPE(sym->st_info) != STT_OBJECT && 609 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 610 continue; 611 612 symn = strt + sym->st_name; 613 if (sym != sl->sl_sym_out && _dl_strcmp(symn, sl->sl_name)) 614 continue; 615 616 /* allow this symbol if we are referring to a function 617 * which has a value, even if section is UNDEF. 618 * this allows &func to refer to PLT as per the 619 * ELF spec. st_value is checked above. 620 * if flags has SYM_PLT set, we must have actual 621 * symbol, so this symbol is skipped. 622 */ 623 if (sym->st_shndx == SHN_UNDEF) { 624 if ((sl->sl_flags & SYM_PLT) || sym->st_value == 0 || 625 ELF_ST_TYPE(sym->st_info) != STT_FUNC) 626 continue; 627 } 628 629 if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { 630 sl->sl_sym_out = sym; 631 sl->sl_obj_out = obj; 632 return 1; 633 } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 634 if (sl->sl_weak_sym_out == NULL) { 635 sl->sl_weak_sym_out = sym; 636 sl->sl_weak_obj_out = obj; 637 } 638 } 639 } 640 return 0; 641} 642 643Elf_Addr 644_dl_find_symbol(const char *name, const Elf_Sym **this, 645 int flags, const Elf_Sym *ref_sym, elf_object_t *req_obj, 646 const elf_object_t **pobj) 647{ 648 const char *p = name; 649 struct dep_node *n, *m; 650 struct symlookup sl = { 651 .sl_name = name, 652 .sl_obj_out = NULL, 653 .sl_weak_obj_out = NULL, 654 .sl_weak_sym_out = NULL, 655 .sl_elf_hash = 0, 656 .sl_flags = flags, 657 }; 658 659 while (*p) { 660 unsigned long g; 661 sl.sl_elf_hash = (sl.sl_elf_hash << 4) + *p++; 662 if ((g = sl.sl_elf_hash & 0xf0000000)) 663 sl.sl_elf_hash ^= g >> 24; 664 sl.sl_elf_hash &= ~g; 665 } 666 667 if (req_obj->dyn.symbolic) 668 if (_dl_find_symbol_obj(req_obj, &sl)) 669 goto found; 670 671 if (flags & SYM_SEARCH_OBJ) { 672 _dl_find_symbol_obj(req_obj, &sl); 673 /* always just fallthrough to 'found' */ 674 } else if (flags & SYM_DLSYM) { 675 if (_dl_find_symbol_obj(req_obj, &sl)) 676 goto found; 677 678 /* weak definition in the specified object is good enough */ 679 if (sl.sl_weak_obj_out != NULL) 680 goto found; 681 682 /* search dlopened obj and all children */ 683 TAILQ_FOREACH(n, &req_obj->load_object->grpsym_list, next_sib) { 684 if (_dl_find_symbol_obj(n->data, &sl)) 685 goto found; 686 } 687 } else { 688 int skip = 0; 689 690 if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT)) 691 skip = 1; 692 693 /* 694 * search dlopened objects: global or req_obj == dlopened_obj 695 * and and it's children 696 */ 697 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 698 if (((n->data->obj_flags & DF_1_GLOBAL) == 0) && 699 (n->data != req_obj->load_object)) 700 continue; 701 702 TAILQ_FOREACH(m, &n->data->grpsym_list, next_sib) { 703 if (skip == 1) { 704 if (m->data == req_obj) { 705 skip = 0; 706 if (flags & SYM_SEARCH_NEXT) 707 continue; 708 } else 709 continue; 710 } 711 if ((flags & SYM_SEARCH_OTHER) && 712 (m->data == req_obj)) 713 continue; 714 if (_dl_find_symbol_obj(m->data, &sl)) 715 goto found; 716 } 717 } 718 } 719 720found: 721 if (sl.sl_sym_out != NULL) { 722 *this = sl.sl_sym_out; 723 } else if (sl.sl_weak_obj_out != NULL) { 724 sl.sl_obj_out = sl.sl_weak_obj_out; 725 *this = sl.sl_weak_sym_out; 726 } else { 727 if ((ref_sym == NULL || 728 (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) && 729 (flags & SYM_WARNNOTFOUND)) 730 _dl_printf("%s:%s: undefined symbol '%s'\n", 731 __progname, req_obj->load_name, name); 732 return (0); 733 } 734 735 if (ref_sym != NULL && ref_sym->st_size != 0 && 736 (ref_sym->st_size != (*this)->st_size) && 737 (ELF_ST_TYPE((*this)->st_info) != STT_FUNC) ) { 738 _dl_printf("%s:%s: %s : WARNING: " 739 "symbol(%s) size mismatch, relink your program\n", 740 __progname, req_obj->load_name, sl.sl_obj_out->load_name, 741 name); 742 } 743 744 if (pobj != NULL) 745 *pobj = sl.sl_obj_out; 746 747 return sl.sl_obj_out->obj_base; 748} 749 750void 751_dl_debug_state(void) 752{ 753 /* Debugger stub */ 754} 755