resolve.c revision 1.95
1/* $OpenBSD: resolve.c,v 1.95 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 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 372 if (gnu_hash) { 373 Elf_Word *hashtab = (Elf_Word *)(gnu_hash + obase); 374 Elf_Word nbuckets = hashtab[0]; 375 Elf_Word nmaskwords = hashtab[2]; 376 377 /* validity check */ 378 if (nbuckets > 0 && (nmaskwords & (nmaskwords - 1)) == 0) { 379 Elf_Word symndx = hashtab[1]; 380 int bloom_size32 = (ELFSIZE / 32) * nmaskwords; 381 382 object->nbuckets = nbuckets; 383 object->symndx_gnu = symndx; 384 object->mask_bm_gnu = nmaskwords - 1; 385 object->shift2_gnu = hashtab[3]; 386 object->bloom_gnu = (Elf_Addr *)(hashtab + 4); 387 object->buckets_gnu = hashtab + 4 + bloom_size32; 388 object->chains_gnu = object->buckets_gnu + nbuckets 389 - symndx; 390 391 /* 392 * If the ELF hash is present, get the total symbol 393 * count ("nchains") from there. Otherwise, count 394 * the entries in the GNU hash chain. 395 */ 396 if (object->Dyn.info[DT_HASH] == 0) { 397 Elf_Word n; 398 399 for (n = 0; n < nbuckets; n++) { 400 Elf_Word bkt = object->buckets_gnu[n]; 401 const Elf_Word *hashval; 402 if (bkt == 0) 403 continue; 404 hashval = &object->chains_gnu[bkt]; 405 do { 406 symndx++; 407 } while ((*hashval++ & 1U) == 0); 408 } 409 object->nchains = symndx; 410 } 411 object->status |= STAT_GNU_HASH; 412 } 413 } 414 if (object->Dyn.info[DT_HASH] != 0) { 415 Elf_Hash_Word *hashtab = 416 (Elf_Hash_Word *)(object->Dyn.info[DT_HASH] + obase); 417 418 object->nchains = hashtab[1]; 419 if (object->nbuckets == 0) { 420 object->nbuckets = hashtab[0]; 421 object->buckets_elf = hashtab + 2; 422 object->chains_elf = object->buckets_elf + 423 object->nbuckets; 424 } 425 } 426 427 object->phdrp = phdrp; 428 object->phdrc = phdrc; 429 object->load_base = lbase; 430 object->obj_base = obase; 431 object->load_name = _dl_strdup(objname); 432 if (object->load_name == NULL) 433 _dl_oom(); 434 object->load_object = _dl_loading_object; 435 if (object->load_object == object) 436 DL_DEB(("head %s\n", object->load_name)); 437 DL_DEB(("obj %s has %s as head\n", object->load_name, 438 _dl_loading_object->load_name )); 439 object->refcount = 0; 440 object->opencount = 0; /* # dlopen() & exe */ 441 object->grprefcount = 0; 442 /* default dev, inode for dlopen-able objects. */ 443 object->dev = 0; 444 object->inode = 0; 445 object->grpsym_gen = 0; 446 TAILQ_INIT(&object->grpref_list); 447 448 if (object->dyn.runpath) 449 object->runpath = _dl_split_path(object->dyn.runpath); 450 /* 451 * DT_RPATH is ignored if DT_RUNPATH is present...except in 452 * the exe, whose DT_RPATH is a fallback for libs that don't 453 * use DT_RUNPATH 454 */ 455 if (object->dyn.rpath && (object->runpath == NULL || 456 objtype == OBJTYPE_EXE)) 457 object->rpath = _dl_split_path(object->dyn.rpath); 458 if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust) 459 _dl_origin_subst(object); 460 461 _dl_trace_object_setup(object); 462 463 return (object); 464} 465 466static void 467_dl_tailq_free(struct dep_node *n) 468{ 469 struct dep_node *next; 470 471 while (n != NULL) { 472 next = TAILQ_NEXT(n, next_sib); 473 _dl_free(n); 474 n = next; 475 } 476} 477 478static elf_object_t *free_objects; 479 480void 481_dl_cleanup_objects() 482{ 483 elf_object_t *nobj, *head; 484 struct dep_node *n, *next; 485 486 n = TAILQ_FIRST(&_dlopened_child_list); 487 while (n != NULL) { 488 next = TAILQ_NEXT(n, next_sib); 489 if (OBJECT_DLREF_CNT(n->data) == 0) { 490 TAILQ_REMOVE(&_dlopened_child_list, n, next_sib); 491 _dl_free(n); 492 } 493 n = next; 494 } 495 496 head = free_objects; 497 free_objects = NULL; 498 while (head != NULL) { 499 _dl_free(head->load_name); 500 _dl_free((char *)head->sod.sod_name); 501 _dl_free_path(head->runpath); 502 _dl_free_path(head->rpath); 503 _dl_free(head->grpsym_vec.vec); 504 _dl_free(head->child_vec.vec); 505 _dl_tailq_free(TAILQ_FIRST(&head->grpref_list)); 506 nobj = head->next; 507 _dl_free(head); 508 head = nobj; 509 } 510} 511 512void 513_dl_remove_object(elf_object_t *object) 514{ 515 object->prev->next = object->next; 516 if (object->next) 517 object->next->prev = object->prev; 518 519 if (_dl_last_object == object) 520 _dl_last_object = object->prev; 521 object_count--; 522 523 object->next = free_objects; 524 free_objects = object; 525} 526 527static int 528matched_symbol(elf_object_t *obj, const Elf_Sym *sym, struct symlookup *sl) 529{ 530 switch (ELF_ST_TYPE(sym->st_info)) { 531 case STT_FUNC: 532 /* 533 * Allow this symbol if we are referring to a function which 534 * has a value, even if section is UNDEF. This allows &func 535 * to refer to PLT as per the ELF spec. If flags has SYM_PLT 536 * set, we must have actual symbol, so this symbol is skipped. 537 */ 538 if ((sl->sl_flags & SYM_PLT) && sym->st_shndx == SHN_UNDEF) 539 return 0; 540 if (sym->st_value == 0) 541 return 0; 542 break; 543 case STT_NOTYPE: 544 case STT_OBJECT: 545 if (sym->st_value == 0) 546 return 0; 547#if 0 548 /* FALLTHROUGH */ 549 case STT_TLS: 550#endif 551 if (sym->st_shndx == SHN_UNDEF) 552 return 0; 553 break; 554 default: 555 return 0; 556 } 557 558 if (sym != sl->sl_out.sym && 559 _dl_strcmp(sl->sl_name, obj->dyn.strtab + sym->st_name)) 560 return 0; 561 562 if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { 563 sl->sl_out.sym = sym; 564 sl->sl_out.obj = obj; 565 return 1; 566 } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 567 if (sl->sl_weak_out.sym == NULL) { 568 sl->sl_weak_out.sym = sym; 569 sl->sl_weak_out.obj = obj; 570 } 571 /* done with this object, but need to check other objects */ 572 return -1; 573 } 574 return 0; 575} 576 577static int 578_dl_find_symbol_obj(elf_object_t *obj, struct symlookup *sl) 579{ 580 const Elf_Sym *symt = obj->dyn.symtab; 581 582 if (obj->status & STAT_GNU_HASH) { 583 uint32_t hash = sl->sl_gnu_hash; 584 Elf_Addr bloom_word; 585 unsigned int h1; 586 unsigned int h2; 587 Elf_Word bucket; 588 const Elf_Word *hashval; 589 590 /* pick right bitmask word from Bloom filter array */ 591 bloom_word = obj->bloom_gnu[(hash / ELFSIZE) & 592 obj->mask_bm_gnu]; 593 594 /* calculate modulus ELFSIZE of gnu hash and its derivative */ 595 h1 = hash & (ELFSIZE - 1); 596 h2 = (hash >> obj->shift2_gnu) & (ELFSIZE - 1); 597 598 /* Filter out the "definitely not in set" queries */ 599 if (((bloom_word >> h1) & (bloom_word >> h2) & 1) == 0) 600 return 0; 601 602 /* Locate hash chain and corresponding value element */ 603 bucket = obj->buckets_gnu[hash % obj->nbuckets]; 604 if (bucket == 0) 605 return 0; 606 hashval = &obj->chains_gnu[bucket]; 607 do { 608 if (((*hashval ^ hash) >> 1) == 0) { 609 const Elf_Sym *sym = symt + 610 (hashval - obj->chains_gnu); 611 612 int r = matched_symbol(obj, sym, sl); 613 if (r) 614 return r > 0; 615 } 616 } while ((*hashval++ & 1U) == 0); 617 } else { 618 Elf_Word si; 619 620 for (si = obj->buckets_elf[sl->sl_elf_hash % obj->nbuckets]; 621 si != STN_UNDEF; si = obj->chains_elf[si]) { 622 const Elf_Sym *sym = symt + si; 623 624 int r = matched_symbol(obj, sym, sl); 625 if (r) 626 return r > 0; 627 } 628 } 629 return 0; 630} 631 632struct sym_res 633_dl_find_symbol(const char *name, int flags, const Elf_Sym *ref_sym, 634 elf_object_t *req_obj) 635{ 636 const unsigned char *p; 637 unsigned char c; 638 struct symlookup sl = { 639 .sl_name = name, 640 .sl_out = { .sym = NULL }, 641 .sl_weak_out = { .sym = NULL }, 642 .sl_elf_hash = 0, 643 .sl_gnu_hash = 5381, 644 .sl_flags = flags, 645 }; 646 647 /* Calculate both hashes in one pass */ 648 for (p = (const unsigned char *)name; (c = *p) != '\0'; p++) { 649 unsigned long g; 650 sl.sl_elf_hash = (sl.sl_elf_hash << 4) + c; 651 if ((g = sl.sl_elf_hash & 0xf0000000)) 652 sl.sl_elf_hash ^= g >> 24; 653 sl.sl_elf_hash &= ~g; 654 sl.sl_gnu_hash = sl.sl_gnu_hash * 33 + c; 655 } 656 657 if (req_obj->dyn.symbolic) 658 if (_dl_find_symbol_obj(req_obj, &sl)) 659 goto found; 660 661 if (flags & SYM_DLSYM) { 662 struct object_vector vec; 663 int i; 664 665 if (_dl_find_symbol_obj(req_obj, &sl)) 666 goto found; 667 668 /* weak definition in the specified object is good enough */ 669 if (sl.sl_weak_out.sym != NULL) 670 goto found; 671 672 /* search dlopened obj and all children */ 673 vec = req_obj->load_object->grpsym_vec; 674 for (i = 0; i < vec.len; i++) { 675 if (vec.vec[i] == req_obj) 676 continue; /* already searched */ 677 if (_dl_find_symbol_obj(vec.vec[i], &sl)) 678 goto found; 679 } 680 } else { 681 struct dep_node *n; 682 struct object_vector vec; 683 int i, skip = 0; 684 685 if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT)) 686 skip = 1; 687 688 /* 689 * search dlopened objects: global or req_obj == dlopened_obj 690 * and its children 691 */ 692 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 693 if (((n->data->obj_flags & DF_1_GLOBAL) == 0) && 694 (n->data != req_obj->load_object)) 695 continue; 696 697 vec = n->data->grpsym_vec; 698 for (i = 0; i < vec.len; i++) { 699 if (skip == 1) { 700 if (vec.vec[i] == req_obj) { 701 skip = 0; 702 if (flags & SYM_SEARCH_NEXT) 703 continue; 704 } else 705 continue; 706 } 707 if ((flags & SYM_SEARCH_OTHER) && 708 (vec.vec[i] == req_obj)) 709 continue; 710 if (_dl_find_symbol_obj(vec.vec[i], &sl)) 711 goto found; 712 } 713 } 714 } 715 716found: 717 if (sl.sl_out.sym == NULL) { 718 if (sl.sl_weak_out.sym != NULL) 719 sl.sl_out = sl.sl_weak_out; 720 else { 721 if ((ref_sym == NULL || 722 (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) && 723 (flags & SYM_WARNNOTFOUND)) 724 _dl_printf("%s:%s: undefined symbol '%s'\n", 725 __progname, req_obj->load_name, name); 726 return (struct sym_res){ NULL, NULL }; 727 } 728 } 729 730 if (ref_sym != NULL && ref_sym->st_size != 0 && 731 (ref_sym->st_size != sl.sl_out.sym->st_size) && 732 (ELF_ST_TYPE(sl.sl_out.sym->st_info) != STT_FUNC) ) { 733 _dl_printf("%s:%s: %s : WARNING: " 734 "symbol(%s) size mismatch, relink your program\n", 735 __progname, req_obj->load_name, sl.sl_out.obj->load_name, 736 name); 737 } 738 739 return sl.sl_out; 740} 741 742void 743_dl_debug_state(void) 744{ 745 /* Debugger stub */ 746} 747