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