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