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