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