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