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