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