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