1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Object file dependent support for a.out format objects. 30 */ 31 #include "_synonyms.h" 32 33 #include <a.out.h> /* Explicitly override M_SEGSIZE */ 34 #include <machdep.h> /* used in M_SROUND */ 35 36 #include <sys/mman.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <dlfcn.h> 42 #include <errno.h> 43 #include <debug.h> 44 #include "_a.out.h" 45 #include "cache_a.out.h" 46 #include "msg.h" 47 #include "_rtld.h" 48 49 /* 50 * Default and secure dependency search paths. 51 */ 52 static Pnode aout_dflt_dirs[] = { 53 { MSG_ORIG(MSG_PTH_USR4LIB), 0, MSG_PTH_USR4LIB_SIZE, 54 LA_SER_DEFAULT, 0, &aout_dflt_dirs[1] }, 55 { MSG_ORIG(MSG_PTH_USRLIB), 0, MSG_PTH_USRLIB_SIZE, 56 LA_SER_DEFAULT, 0, &aout_dflt_dirs[2] }, 57 { MSG_ORIG(MSG_PTH_USRLCLIB), 0, MSG_PTH_USRLCLIB_SIZE, 58 LA_SER_DEFAULT, 0, 0 } 59 }; 60 61 static Pnode aout_secure_dirs[] = { 62 { MSG_ORIG(MSG_PTH_USR4LIB), 0, MSG_PTH_USR4LIB_SIZE, 63 LA_SER_SECURE, 0, &aout_secure_dirs[1] }, 64 { MSG_ORIG(MSG_PTH_USRLIB), 0, MSG_PTH_USRLIB_SIZE, 65 LA_SER_SECURE, 0, &aout_secure_dirs[2] }, 66 { MSG_ORIG(MSG_PTH_USRUCBLIB), 0, MSG_PTH_USRUCBLIB_SIZE, 67 LA_SER_SECURE, 0, &aout_secure_dirs[3] }, 68 { MSG_ORIG(MSG_PTH_USRLCLIB), 0, MSG_PTH_USRLCLIB_SIZE, 69 LA_SER_SECURE, 0, 0 } 70 }; 71 72 /* 73 * Defines for local functions. 74 */ 75 static int aout_are_u(); 76 static ulong_t aout_entry_pt(); 77 static Rt_map *aout_map_so(); 78 static void aout_unmap_so(); 79 static int aout_needed(); 80 extern Sym *aout_lookup_sym(); 81 static Sym *aout_find_sym(); 82 static char *aout_get_so(); 83 static Pnode *aout_fix_name(); 84 static void aout_dladdr(); 85 static Sym *aout_dlsym_handle(); 86 static int aout_verify_vers(); 87 88 /* 89 * Functions and data accessed through indirect pointers. 90 */ 91 Fct aout_fct = { 92 aout_are_u, 93 aout_entry_pt, 94 aout_map_so, 95 aout_unmap_so, 96 aout_needed, 97 aout_lookup_sym, 98 aout_reloc, 99 aout_dflt_dirs, 100 aout_secure_dirs, 101 aout_fix_name, 102 aout_get_so, 103 aout_dladdr, 104 aout_dlsym_handle, 105 aout_verify_vers, 106 aout_set_prot 107 }; 108 109 110 /* 111 * In 4.x, a needed file or a dlopened file that was a simple file name implied 112 * that the file be found in the present working directory. To simulate this 113 * lookup within the elf rules it is necessary to add a proceeding `./' to the 114 * filename. 115 */ 116 static Pnode * 117 aout_fix_name(const char *name, Rt_map *clmp) 118 { 119 size_t len; 120 Pnode *pnp; 121 122 if ((pnp = calloc(1, sizeof (Pnode))) == 0) 123 return (0); 124 125 /* 126 * Check for slash in name, if none, prepend "./", otherwise just 127 * return name given. 128 */ 129 if (strchr(name, '/')) { 130 len = strlen(name) + 1; 131 if ((pnp->p_name = malloc(len)) != 0) 132 (void) strcpy((char *)pnp->p_name, name); 133 } else { 134 len = strlen(name) + 3; 135 if ((pnp->p_name = malloc(len)) != 0) 136 (void) snprintf((char *)pnp->p_name, len, 137 MSG_ORIG(MSG_FMT_4XPATH), name); 138 } 139 140 if (pnp->p_name) { 141 pnp->p_len = len; 142 DBG_CALL(Dbg_file_fixname(LIST(clmp), pnp->p_name, name)); 143 return (pnp); 144 } 145 free(pnp); 146 return (0); 147 } 148 149 /* 150 * Determine if we have been given an A_OUT file. Returns 1 if true. 151 */ 152 static int 153 aout_are_u() 154 { 155 struct exec *exec; 156 157 /* LINTED */ 158 exec = (struct exec *)fmap->fm_maddr; 159 if (fmap->fm_fsize < sizeof (exec) || (exec->a_machtype != M_SPARC) || 160 (N_BADMAG(*exec))) { 161 return (0); 162 } 163 return (1); 164 } 165 166 /* 167 * Return the entry point the A_OUT executable. This is always zero. 168 */ 169 static ulong_t 170 aout_entry_pt() 171 { 172 return (0); 173 } 174 175 /* 176 * Unmap a given A_OUT shared object from the address space. 177 */ 178 static void 179 aout_unmap_so(Rt_map *lmp) 180 { 181 Mmap *immap = MMAPS(lmp); 182 183 (void) munmap(immap->m_vaddr, immap->m_msize); 184 } 185 186 /* 187 * Dummy versioning interface - real functionality is only applicable to elf. 188 */ 189 static int 190 aout_verify_vers() 191 { 192 return (1); 193 } 194 195 /* 196 * Search through the dynamic section for DT_NEEDED entries and perform one 197 * of two functions. If only the first argument is specified then load the 198 * defined shared object, otherwise add the link map representing the 199 * defined link map the the dlopen list. 200 */ 201 static int 202 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 203 { 204 void *need; 205 206 for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need]; 207 need != &TEXTBASE(clmp)[0]; 208 need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) { 209 Rt_map *nlmp; 210 char *name; 211 Pnode *pnp; 212 213 name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name]; 214 215 if (((Lnk_obj *)(need))->lo_library) { 216 /* 217 * If lo_library field is not NULL then this needed 218 * library was linked in using the "-l" option. 219 * Thus we need to rebuild the library name before 220 * trying to load it. 221 */ 222 Pnode *dir, *dirlist = (Pnode *)0; 223 char *file; 224 size_t len; 225 226 /* 227 * Allocate name length plus 20 for full library name. 228 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20 229 */ 230 len = strlen(name) + 20; 231 if ((file = malloc(len)) == 0) 232 return (0); 233 (void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB), 234 name, ((Lnk_obj *)(need))->lo_major, 235 ((Lnk_obj *)(need))->lo_minor); 236 237 DBG_CALL(Dbg_libs_find(lml, file)); 238 239 /* 240 * We need to determine what filename will match the 241 * the filename specified (ie, a libc.so.1.2 may match 242 * to a libc.so.1.3). It's the real pathname that is 243 * recorded in the link maps. If we are presently 244 * being traced, skip this pathname generation so 245 * that we fall through into load_so() to print the 246 * appropriate diagnostics. I don't like this at all. 247 */ 248 if (lml->lm_flags & LML_FLG_TRC_ENABLE) 249 name = file; 250 else { 251 char *path = (char *)0; 252 253 for (dir = get_next_dir(&dirlist, clmp, 0); dir; 254 dir = get_next_dir(&dirlist, clmp, 0)) { 255 if (dir->p_name == 0) 256 continue; 257 258 if (path = 259 aout_get_so(dir->p_name, file)) 260 break; 261 } 262 if (!path) { 263 eprintf(lml, ERR_FATAL, 264 MSG_INTL(MSG_SYS_OPEN), file, 265 strerror(ENOENT)); 266 return (0); 267 } 268 name = path; 269 } 270 if ((pnp = expand_paths(clmp, name, 0, 0)) == 0) 271 return (0); 272 } else { 273 /* 274 * If the library is specified as a pathname, see if 275 * it must be fixed to specify the current working 276 * directory (ie. libc.so.1.2 -> ./libc.so.1.2). 277 */ 278 if ((pnp = aout_fix_name(name, clmp)) == 0) 279 return (0); 280 } 281 282 DBG_CALL(Dbg_file_needed(clmp, name)); 283 284 nlmp = load_one(lml, lmco, pnp, clmp, MODE(clmp), 0, 0, 285 in_nfavl); 286 remove_pnode(pnp); 287 if (((nlmp == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) && 288 ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0)) 289 return (0); 290 } 291 292 return (1); 293 } 294 295 static Sym * 296 aout_symconvert(struct nlist *sp) 297 { 298 static Sym sym; 299 300 sym.st_value = sp->n_value; 301 sym.st_size = 0; 302 sym.st_info = 0; 303 sym.st_other = 0; 304 switch (sp->n_type) { 305 case N_EXT + N_ABS: 306 sym.st_shndx = SHN_ABS; 307 break; 308 case N_COMM: 309 sym.st_shndx = SHN_COMMON; 310 break; 311 case N_EXT + N_UNDF: 312 sym.st_shndx = SHN_UNDEF; 313 break; 314 default: 315 sym.st_shndx = 0; 316 break; 317 } 318 return (&sym); 319 } 320 321 /* 322 * Process a.out format commons. 323 */ 324 static struct nlist * 325 aout_find_com(struct nlist *sp, const char *name) 326 { 327 static struct rtc_symb *rtcp = 0; 328 struct rtc_symb *rs, * trs; 329 const char *sl; 330 char *cp; 331 332 /* 333 * See if common is already allocated. 334 */ 335 trs = rtcp; 336 while (trs) { 337 sl = name; 338 cp = trs->rtc_sp->n_un.n_name; 339 while (*sl == *cp++) 340 if (*sl++ == '\0') 341 return (trs->rtc_sp); 342 trs = trs->rtc_next; 343 } 344 345 /* 346 * If we got here, common is not already allocated so allocate it. 347 */ 348 if ((rs = malloc(sizeof (struct rtc_symb))) == 0) 349 return (0); 350 if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == 0) 351 return (0); 352 trs = rtcp; 353 rtcp = rs; 354 rs->rtc_next = trs; 355 *(rs->rtc_sp) = *sp; 356 if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == 0) 357 return (0); 358 (void) strcpy(rs->rtc_sp->n_un.n_name, name); 359 rs->rtc_sp->n_type = N_COMM; 360 if ((rs->rtc_sp->n_value = (long)calloc(rs->rtc_sp->n_value, 1)) == 0) 361 return (0); 362 return (rs->rtc_sp); 363 } 364 365 /* 366 * Find a.out format symbol in the specified link map. Unlike the sister 367 * elf routine we re-calculate the symbols hash value for each link map 368 * we're looking at. 369 */ 370 static struct nlist * 371 aout_findsb(const char *aname, Rt_map *lmp, int flag) 372 { 373 const char *name = aname; 374 char *cp; 375 struct fshash *p; 376 int i; 377 struct nlist *sp; 378 ulong_t hval = 0; 379 380 #define HASHMASK 0x7fffffff 381 #define RTHS 126 382 383 /* 384 * The name passed to us is in ELF format, thus it is necessary to 385 * map this back to the A_OUT format to compute the hash value (see 386 * mapping rules in aout_lookup_sym()). Basically the symbols are 387 * mapped according to whether a leading `.' exists. 388 * 389 * elf symbol a.out symbol 390 * i. .bar -> .bar (LKUP_LDOT) 391 * ii. .nuts -> nuts 392 * iii. foo -> _foo 393 */ 394 if (*name == '.') { 395 if (!(flag & LKUP_LDOT)) 396 name++; 397 } else 398 hval = '_'; 399 400 while (*name) 401 hval = (hval << 1) + *name++; 402 hval = hval & HASHMASK; 403 404 i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS : 405 AOUTDYN(lmp)->v2->ld_buckets); 406 p = LM2LP(lmp)->lp_hash + i; 407 408 if (p->fssymbno != -1) 409 do { 410 sp = &LM2LP(lmp)->lp_symtab[p->fssymbno]; 411 cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; 412 name = aname; 413 if (*name == '.') { 414 if (!(flag & LKUP_LDOT)) 415 name++; 416 } else { 417 cp++; 418 } 419 while (*name == *cp++) { 420 if (*name++ == '\0') 421 return (sp); /* found */ 422 } 423 if (p->next == 0) 424 return (0); /* not found */ 425 else 426 continue; 427 } while ((p = &LM2LP(lmp)->lp_hash[p->next]) != 0); 428 return (0); 429 } 430 431 /* 432 * The symbol name we have been asked to look up is in A_OUT format, this 433 * symbol is mapped to the appropriate ELF format which is the standard by 434 * which symbols are passed around ld.so.1. The symbols are mapped 435 * according to whether a leading `_' or `.' exists. 436 * 437 * a.out symbol elf symbol 438 * i. _foo -> foo 439 * ii. .bar -> .bar (LKUP_LDOT) 440 * iii. nuts -> .nuts 441 */ 442 Sym * 443 aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 444 { 445 char name[PATH_MAX]; 446 Slookup sl = *slp; 447 448 DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_imap), slp->sl_name)); 449 450 if (*sl.sl_name == '_') 451 ++sl.sl_name; 452 else if (*sl.sl_name == '.') 453 sl.sl_flags |= LKUP_LDOT; 454 else { 455 name[0] = '.'; 456 (void) strcpy(&name[1], sl.sl_name); 457 sl.sl_name = name; 458 } 459 460 /* 461 * Call the generic lookup routine to cycle through the specified 462 * link maps. 463 */ 464 return (lookup_sym(&sl, dlmp, binfo, in_nfavl)); 465 } 466 467 /* 468 * Symbol lookup for an a.out format module. 469 */ 470 /* ARGSUSED3 */ 471 static Sym * 472 aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 473 { 474 const char *name = slp->sl_name; 475 Rt_map *ilmp = slp->sl_imap; 476 struct nlist *sp; 477 478 DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_AOUT))); 479 480 if (sp = aout_findsb(name, ilmp, slp->sl_flags)) { 481 if (sp->n_value != 0) { 482 /* 483 * is it a common? 484 */ 485 if (sp->n_type == (N_EXT + N_UNDF)) { 486 if ((sp = aout_find_com(sp, name)) == 0) 487 return ((Sym *)0); 488 } 489 *dlmp = ilmp; 490 *binfo |= DBG_BINFO_FOUND; 491 return (aout_symconvert(sp)); 492 } 493 } 494 return ((Sym *)0); 495 } 496 497 /* 498 * Map in an a.out format object. 499 * Takes an open file descriptor for the object to map and 500 * its pathname; returns a pointer to a Rt_map structure 501 * for this object, or 0 on error. 502 */ 503 static Rt_map * 504 aout_map_so(Lm_list *lml, Aliste lmco, const char *pname, const char *oname, 505 int fd) 506 { 507 struct exec *exec; /* working area for object headers */ 508 caddr_t addr; /* mmap result temporary */ 509 struct link_dynamic *ld; /* dynamic pointer of object mapped */ 510 size_t size; /* size of object */ 511 Rt_map *lmp; /* link map created */ 512 int err; 513 struct nlist *nl; 514 515 /* 516 * Map text and allocate enough address space to fit the whole 517 * library. Note that we map enough to catch the first symbol 518 * in the symbol table and thereby avoid an "lseek" & "read" 519 * pair to pick it up. 520 */ 521 /* LINTED */ 522 exec = (struct exec *)fmap->fm_maddr; 523 size = max(SIZE(*exec), N_SYMOFF(*exec) + sizeof (struct nlist)); 524 if ((addr = mmap(0, size, (PROT_READ | PROT_EXEC), MAP_PRIVATE, 525 fd, 0)) == MAP_FAILED) { 526 err = errno; 527 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname, 528 strerror(err)); 529 return (0); 530 } 531 532 /* 533 * Grab the first symbol entry while we've got it mapped aligned 534 * to file addresses. We assume that this symbol describes the 535 * object's link_dynamic. 536 */ 537 /* LINTED */ 538 nl = (struct nlist *)&addr[N_SYMOFF(*exec)]; 539 /* LINTED */ 540 ld = (struct link_dynamic *)&addr[nl->n_value]; 541 542 /* 543 * Map the initialized data portion of the file to the correct 544 * point in the range of allocated addresses. This will leave 545 * some portion of the data segment "doubly mapped" on machines 546 * where the text/data relocation alignment is not on a page 547 * boundaries. However, leaving the file mapped has the double 548 * advantage of both saving the munmap system call and of leaving 549 * us a contiguous chunk of address space devoted to the object -- 550 * in case we need to unmap it all later. 551 */ 552 if (mmap((caddr_t)(addr + M_SROUND(exec->a_text)), 553 (int)exec->a_data, (PROT_READ | PROT_WRITE | PROT_EXEC), 554 (MAP_FIXED | MAP_PRIVATE), fd, (off_t)exec->a_text) == MAP_FAILED) { 555 err = errno; 556 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP), pname, 557 strerror(err)); 558 return (0); 559 } 560 561 /* 562 * Allocate pages for the object's bss, if necessary. 563 */ 564 if (exec->a_bss != 0) { 565 if (dz_map(lml, addr + M_SROUND(exec->a_text) + exec->a_data, 566 (int)exec->a_bss, PROT_READ | PROT_WRITE | PROT_EXEC, 567 MAP_FIXED | MAP_PRIVATE) == MAP_FAILED) 568 goto error; 569 } 570 571 /* 572 * Create link map structure for newly mapped shared object. 573 */ 574 ld->v2 = (struct link_dynamic_2 *)((int)ld->v2 + (int)addr); 575 if (!(lmp = aout_new_lm(lml, pname, oname, ld, addr, size, lmco))) 576 goto error; 577 578 return (lmp); 579 580 /* 581 * Error returns: close off file and free address space. 582 */ 583 error: 584 (void) munmap((caddr_t)addr, size); 585 return (0); 586 } 587 588 /* 589 * Create a new Rt_map structure for an a.out format object and 590 * initializes all values. 591 */ 592 Rt_map * 593 aout_new_lm(Lm_list *lml, const char *pname, const char *oname, 594 struct link_dynamic *ld, caddr_t addr, size_t size, Aliste lmco) 595 { 596 Rt_map *lmp; 597 caddr_t offset; 598 599 DBG_CALL(Dbg_file_aout(lml, pname, (ulong_t)ld, (ulong_t)addr, 600 (ulong_t)size, lml->lm_lmidstr, lmco)); 601 602 /* 603 * Allocate space for the link-map and private a.out information. Once 604 * these are allocated and initialized, we can use remove_so(0, lmp) to 605 * tear down the link-map should any failures occur. 606 */ 607 if ((lmp = calloc(sizeof (Rt_map), 1)) == 0) 608 return (0); 609 if ((AOUTPRV(lmp) = calloc(sizeof (Rt_aoutp), 1)) == 0) { 610 free(lmp); 611 return (0); 612 } 613 if ((((Rt_aoutp *)AOUTPRV(lmp))->lm_lpd = 614 calloc(sizeof (struct ld_private), 1)) == 0) { 615 free(AOUTPRV(lmp)); 616 free(lmp); 617 return (0); 618 } 619 620 /* 621 * All fields not filled in were set to 0 by calloc. 622 */ 623 ORIGNAME(lmp) = PATHNAME(lmp) = NAME(lmp) = (char *)pname; 624 ADDR(lmp) = (ulong_t)addr; 625 MSIZE(lmp) = (ulong_t)size; 626 SYMINTP(lmp) = aout_find_sym; 627 FCT(lmp) = &aout_fct; 628 LIST(lmp) = lml; 629 THREADID(lmp) = rt_thr_self(); 630 OBJFLTRNDX(lmp) = FLTR_DISABLED; 631 SORTVAL(lmp) = -1; 632 633 /* 634 * Specific settings for a.out format. 635 */ 636 if (lml->lm_head == 0) { 637 offset = (caddr_t)MAIN_BASE; 638 FLAGS(lmp) |= FLG_RT_FIXED; 639 } else 640 offset = addr; 641 642 ETEXT(lmp) = (ulong_t)&offset[ld->v2->ld_text]; 643 644 /* 645 * Create a mapping descriptor to describe the whole object as a single 646 * mapping. 647 */ 648 if ((MMAPS(lmp) = calloc(2, sizeof (Mmap))) == 0) 649 return (0); 650 MMAPS(lmp)->m_vaddr = offset; 651 /* LINTED */ 652 MMAPS(lmp)->m_msize = max(SIZE(*(struct exec *)offset), 653 N_SYMOFF((*(struct exec *)offset)) + sizeof (struct nlist)); 654 MMAPS(lmp)->m_fsize = MMAPS(lmp)->m_msize; 655 MMAPCNT(lmp) = 1; 656 657 /* 658 * Fill in all AOUT information. 659 */ 660 AOUTDYN(lmp) = ld; 661 if ((RPATH(lmp) = (char *)&offset[ld->v2->ld_rules]) == offset) 662 RPATH(lmp) = 0; 663 LM2LP(lmp)->lp_symbol_base = addr; 664 /* LINTED */ 665 LM2LP(lmp)->lp_plt = (struct jbind *)(&addr[JMPOFF(ld)]); 666 LM2LP(lmp)->lp_rp = 667 /* LINTED */ 668 (struct relocation_info *)(&offset[RELOCOFF(ld)]); 669 /* LINTED */ 670 LM2LP(lmp)->lp_hash = (struct fshash *)(&offset[HASHOFF(ld)]); 671 /* LINTED */ 672 LM2LP(lmp)->lp_symtab = (struct nlist *)(&offset[SYMOFF(ld)]); 673 LM2LP(lmp)->lp_symstr = &offset[STROFF(ld)]; 674 LM2LP(lmp)->lp_textbase = offset; 675 LM2LP(lmp)->lp_refcnt++; 676 LM2LP(lmp)->lp_dlp = NULL; 677 678 if (rtld_flags & RT_FL_RELATIVE) 679 FLAGS1(lmp) |= FL1_RT_RELATIVE; 680 681 if ((CONDVAR(lmp) = rt_cond_create()) == 0) { 682 remove_so(0, lmp); 683 return (0); 684 } 685 if (oname && ((append_alias((lmp), oname, 0)) == 0)) { 686 remove_so(0, lmp); 687 return (0); 688 } 689 690 /* 691 * Add the mapped object to the end of the link map list. 692 */ 693 lm_append(lml, lmco, lmp); 694 return (lmp); 695 } 696 697 /* 698 * Function to correct protection settings. 699 * Segments are all mapped initially with permissions as given in 700 * the segment header, but we need to turn on write permissions 701 * on a text segment if there are any relocations against that segment, 702 * and them turn write permission back off again before returning control 703 * to the program. This function turns the permission on or off depending 704 * on the value of the argument. 705 */ 706 int 707 aout_set_prot(Rt_map *lmp, int permission) 708 { 709 int prot; /* protection setting */ 710 caddr_t et; /* cached _etext of object */ 711 size_t size; /* size of text segment */ 712 713 DBG_CALL(Dbg_file_prot(lmp, permission)); 714 715 et = (caddr_t)ETEXT(lmp); 716 size = M_PROUND((ulong_t)(et - TEXTBASE(lmp))); 717 prot = PROT_READ | PROT_EXEC | permission; 718 if (mprotect((caddr_t)TEXTBASE(lmp), size, prot) == -1) { 719 int err = errno; 720 721 eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_SYS_MPROT), 722 NAME(lmp), strerror(err)); 723 return (0); 724 } 725 return (1); 726 } 727 728 /* 729 * Build full pathname of shared object from the given directory name and 730 * filename. 731 */ 732 static char * 733 aout_get_so(const char *dir, const char *file) 734 { 735 struct db *dbp; 736 char *path = NULL; 737 738 if (dbp = lo_cache(dir)) { 739 path = ask_db(dbp, file); 740 } 741 return (path); 742 } 743 744 /* 745 * Determine the symbol location of an address within a link-map. Look for 746 * the nearest symbol (whoes value is less than or equal to the required 747 * address). This is the object specific part of dladdr(). 748 */ 749 static void 750 aout_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, 751 int flags) 752 { 753 ulong_t ndx, cnt, base, _value; 754 struct nlist *sym, *_sym; 755 756 cnt = ((int)LM2LP(lmp)->lp_symstr - (int)LM2LP(lmp)->lp_symtab) / 757 sizeof (struct nlist); 758 sym = LM2LP(lmp)->lp_symtab; 759 760 if (FLAGS(lmp) & FLG_RT_FIXED) 761 base = 0; 762 else 763 base = ADDR(lmp); 764 765 for (_sym = 0, _value = 0, ndx = 0; ndx < cnt; ndx++, sym++) { 766 ulong_t value; 767 768 if (sym->n_type == (N_EXT + N_UNDF)) 769 continue; 770 771 value = sym->n_value + base; 772 if (value > addr) 773 continue; 774 if (value < _value) 775 continue; 776 777 _sym = sym; 778 _value = value; 779 780 if (value == addr) 781 break; 782 } 783 784 if (_sym) { 785 int _flags = flags & RTLD_DL_MASK; 786 787 /* 788 * The only way we can create a symbol entry is to use 789 * aout_symconvert(), however this results in us pointing to 790 * static data that could be overridden. In addition the AOUT 791 * symbol format doesn't give us everything an ELF symbol does. 792 * So, unless we get convinced otherwise, don't bother returning 793 * a symbol entry for AOUT's. 794 */ 795 if (_flags == RTLD_DL_SYMENT) 796 *info = 0; 797 else if (_flags == RTLD_DL_LINKMAP) 798 *info = (void *)lmp; 799 800 dlip->dli_sname = &LM2LP(lmp)->lp_symstr[_sym->n_un.n_strx]; 801 dlip->dli_saddr = (void *)_value; 802 } 803 } 804 805 /* 806 * Continue processing a dlsym request. Lookup the required symbol in each 807 * link-map specified by the handle. Note, that because this lookup is against 808 * individual link-maps we don't need to supply a starting link-map to the 809 * lookup routine (see lookup_sym():analyze.c). 810 */ 811 Sym * 812 aout_dlsym_handle(Grp_hdl * ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo, 813 int *in_nfavl) 814 { 815 Sym *sym; 816 char buffer[PATH_MAX]; 817 Slookup sl; 818 819 buffer[0] = '_'; 820 (void) strcpy(&buffer[1], slp->sl_name); 821 822 if ((sym = dlsym_handle(ghp, slp, _lmp, binfo, in_nfavl)) != 0) 823 return (sym); 824 825 /* 826 * Symbol not found as supplied. However, most of our symbols will 827 * be in the "C" name space, where the implementation prepends a "_" 828 * to the symbol as it emits it. Therefore, attempt to find the 829 * symbol with the "_" prepend. 830 */ 831 sl = *slp; 832 sl.sl_name = (const char *)buffer; 833 834 return (dlsym_handle(ghp, &sl, _lmp, binfo, in_nfavl)); 835 } 836