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