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 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(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(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(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(pname, (ulong_t)ld, (ulong_t)addr, 596 (ulong_t)size)); 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 628 /* 629 * Specific settings for a.out format. 630 */ 631 if (lml->lm_head == 0) { 632 offset = (caddr_t)MAIN_BASE; 633 FLAGS(lmp) |= FLG_RT_FIXED; 634 } else 635 offset = addr; 636 637 ETEXT(lmp) = (ulong_t)&offset[ld->v2->ld_text]; 638 639 /* 640 * Create a mapping descriptor to describe the whole object as a single 641 * mapping. 642 */ 643 if ((MMAPS(lmp) = calloc(2, sizeof (Mmap))) == 0) 644 return (0); 645 MMAPS(lmp)->m_vaddr = offset; 646 /* LINTED */ 647 MMAPS(lmp)->m_msize = max(SIZE(*(struct exec *)offset), 648 N_SYMOFF((*(struct exec *)offset)) + sizeof (struct nlist)); 649 MMAPS(lmp)->m_fsize = MMAPS(lmp)->m_msize; 650 MMAPCNT(lmp) = 1; 651 652 /* 653 * Fill in all AOUT information. 654 */ 655 AOUTDYN(lmp) = ld; 656 if ((RPATH(lmp) = (char *)&offset[ld->v2->ld_rules]) == offset) 657 RPATH(lmp) = 0; 658 LM2LP(lmp)->lp_symbol_base = addr; 659 /* LINTED */ 660 LM2LP(lmp)->lp_plt = (struct jbind *)(&addr[JMPOFF(ld)]); 661 LM2LP(lmp)->lp_rp = 662 /* LINTED */ 663 (struct relocation_info *)(&offset[RELOCOFF(ld)]); 664 /* LINTED */ 665 LM2LP(lmp)->lp_hash = (struct fshash *)(&offset[HASHOFF(ld)]); 666 /* LINTED */ 667 LM2LP(lmp)->lp_symtab = (struct nlist *)(&offset[SYMOFF(ld)]); 668 LM2LP(lmp)->lp_symstr = &offset[STROFF(ld)]; 669 LM2LP(lmp)->lp_textbase = offset; 670 LM2LP(lmp)->lp_refcnt++; 671 LM2LP(lmp)->lp_dlp = NULL; 672 673 if (rtld_flags & RT_FL_RELATIVE) 674 FLAGS1(lmp) |= FL1_RT_RELATIVE; 675 676 if ((CONDVAR(lmp) = rt_cond_create()) == 0) { 677 remove_so(0, lmp); 678 return (0); 679 } 680 if (oname && ((append_alias((lmp), oname, 0)) == 0)) { 681 remove_so(0, lmp); 682 return (0); 683 } 684 685 /* 686 * Add the mapped object to the end of the link map list. 687 */ 688 lm_append(lml, lmco, lmp); 689 return (lmp); 690 } 691 692 /* 693 * Function to correct protection settings. 694 * Segments are all mapped initially with permissions as given in 695 * the segment header, but we need to turn on write permissions 696 * on a text segment if there are any relocations against that segment, 697 * and them turn write permission back off again before returning control 698 * to the program. This function turns the permission on or off depending 699 * on the value of the argument. 700 */ 701 int 702 aout_set_prot(Rt_map *lm, int permission) 703 { 704 int prot; /* protection setting */ 705 caddr_t et; /* cached _etext of object */ 706 size_t size; /* size of text segment */ 707 708 DBG_CALL(Dbg_file_prot(NAME(lm), permission)); 709 710 et = (caddr_t)ETEXT(lm); 711 size = M_PROUND((ulong_t)(et - TEXTBASE(lm))); 712 prot = PROT_READ | PROT_EXEC | permission; 713 if (mprotect((caddr_t)TEXTBASE(lm), size, prot) == -1) { 714 int err = errno; 715 716 eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_MPROT), NAME(lm), 717 strerror(err)); 718 return (0); 719 } 720 return (1); 721 } 722 723 /* 724 * Build full pathname of shared object from the given directory name and 725 * filename. 726 */ 727 static char * 728 aout_get_so(const char *dir, const char *file) 729 { 730 struct db *dbp; 731 char *path = NULL; 732 733 if (dbp = lo_cache(dir)) { 734 path = ask_db(dbp, file); 735 } 736 return (path); 737 } 738 739 /* 740 * Determine the symbol location of an address within a link-map. Look for 741 * the nearest symbol (whoes value is less than or equal to the required 742 * address). This is the object specific part of dladdr(). 743 */ 744 static void 745 aout_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, 746 int flags) 747 { 748 ulong_t ndx, cnt, base, _value; 749 struct nlist *sym, *_sym; 750 751 cnt = ((int)LM2LP(lmp)->lp_symstr - (int)LM2LP(lmp)->lp_symtab) / 752 sizeof (struct nlist); 753 sym = LM2LP(lmp)->lp_symtab; 754 755 if (FLAGS(lmp) & FLG_RT_FIXED) 756 base = 0; 757 else 758 base = ADDR(lmp); 759 760 for (_sym = 0, _value = 0, ndx = 0; ndx < cnt; ndx++, sym++) { 761 ulong_t value; 762 763 if (sym->n_type == (N_EXT + N_UNDF)) 764 continue; 765 766 value = sym->n_value + base; 767 if (value > addr) 768 continue; 769 if (value < _value) 770 continue; 771 772 _sym = sym; 773 _value = value; 774 775 if (value == addr) 776 break; 777 } 778 779 if (_sym) { 780 int _flags = flags & RTLD_DL_MASK; 781 782 /* 783 * The only way we can create a symbol entry is to use 784 * aout_symconvert(), however this results in us pointing to 785 * static data that could be overridden. In addition the AOUT 786 * symbol format doesn't give us everything an ELF symbol does. 787 * So, unless we get convinced otherwise, don't bother returning 788 * a symbol entry for AOUT's. 789 */ 790 if (_flags == RTLD_DL_SYMENT) 791 *info = 0; 792 else if (_flags == RTLD_DL_LINKMAP) 793 *info = (void *)lmp; 794 795 dlip->dli_sname = &LM2LP(lmp)->lp_symstr[_sym->n_un.n_strx]; 796 dlip->dli_saddr = (void *)_value; 797 } 798 } 799 800 /* 801 * Continue processing a dlsym request. Lookup the required symbol in each 802 * link-map specified by the handle. Note, that because this lookup is against 803 * individual link-maps we don't need to supply a starting link-map to the 804 * lookup routine (see lookup_sym():analyze.c). 805 */ 806 Sym * 807 aout_dlsym_handle(Grp_hdl * ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo) 808 { 809 Sym *sym; 810 char buffer[PATH_MAX]; 811 Slookup sl; 812 813 buffer[0] = '_'; 814 (void) strcpy(&buffer[1], slp->sl_name); 815 816 if ((sym = dlsym_handle(ghp, slp, _lmp, binfo)) != 0) 817 return (sym); 818 819 /* 820 * Symbol not found as supplied. However, most of our symbols will 821 * be in the "C" name space, where the implementation prepends a "_" 822 * to the symbol as it emits it. Therefore, attempt to find the 823 * symbol with the "_" prepend. 824 */ 825 sl = *slp; 826 sl.sl_name = (const char *)buffer; 827 828 return (dlsym_handle(ghp, &sl, _lmp, binfo)); 829 } 830