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 2006 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 pnp->p_orig = PN_SER_NEEDED; 143 DBG_CALL(Dbg_file_fixname(LIST(clmp), pnp->p_name, name)); 144 return (pnp); 145 } 146 free(pnp); 147 return (0); 148 } 149 150 /* 151 * Determine if we have been given an A_OUT file. Returns 1 if true. 152 */ 153 static int 154 aout_are_u() 155 { 156 struct exec *exec; 157 158 /* LINTED */ 159 exec = (struct exec *)fmap->fm_maddr; 160 if (fmap->fm_fsize < sizeof (exec) || (exec->a_machtype != M_SPARC) || 161 (N_BADMAG(*exec))) { 162 return (0); 163 } 164 return (1); 165 } 166 167 /* 168 * Return the entry point the A_OUT executable. This is always zero. 169 */ 170 static ulong_t 171 aout_entry_pt() 172 { 173 return (0); 174 } 175 176 /* 177 * Unmap a given A_OUT shared object from the address space. 178 */ 179 static void 180 aout_unmap_so(Rt_map *lmp) 181 { 182 Mmap *immap = MMAPS(lmp); 183 184 (void) munmap(immap->m_vaddr, immap->m_msize); 185 } 186 187 /* 188 * Dummy versioning interface - real functionality is only applicable to elf. 189 */ 190 static int 191 aout_verify_vers() 192 { 193 return (1); 194 } 195 196 /* 197 * Search through the dynamic section for DT_NEEDED entries and perform one 198 * of two functions. If only the first argument is specified then load the 199 * defined shared object, otherwise add the link map representing the 200 * defined link map the the dlopen list. 201 */ 202 static int 203 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp) 204 { 205 void *need; 206 207 for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need]; 208 need != &TEXTBASE(clmp)[0]; 209 need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) { 210 Rt_map *nlmp; 211 char *name; 212 Pnode *pnp; 213 214 name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name]; 215 216 if (((Lnk_obj *)(need))->lo_library) { 217 /* 218 * If lo_library field is not NULL then this needed 219 * library was linked in using the "-l" option. 220 * Thus we need to rebuild the library name before 221 * trying to load it. 222 */ 223 Pnode *dir, *dirlist = (Pnode *)0; 224 char *file; 225 size_t len; 226 227 /* 228 * Allocate name length plus 20 for full library name. 229 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20 230 */ 231 len = strlen(name) + 20; 232 if ((file = malloc(len)) == 0) 233 return (0); 234 (void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB), 235 name, ((Lnk_obj *)(need))->lo_major, 236 ((Lnk_obj *)(need))->lo_minor); 237 238 DBG_CALL(Dbg_libs_find(lml, file)); 239 240 /* 241 * We need to determine what filename will match the 242 * the filename specified (ie, a libc.so.1.2 may match 243 * to a libc.so.1.3). It's the real pathname that is 244 * recorded in the link maps. If we are presently 245 * being traced, skip this pathname generation so 246 * that we fall through into load_so() to print the 247 * appropriate diagnostics. I don't like this at all. 248 */ 249 if (lml->lm_flags & LML_FLG_TRC_ENABLE) 250 name = file; 251 else { 252 char *path = (char *)0; 253 254 for (dir = get_next_dir(&dirlist, clmp, 0); dir; 255 dir = get_next_dir(&dirlist, clmp, 0)) { 256 if (dir->p_name == 0) 257 continue; 258 259 if (path = 260 aout_get_so(dir->p_name, file)) 261 break; 262 } 263 if (!path) { 264 eprintf(lml, ERR_FATAL, 265 MSG_INTL(MSG_SYS_OPEN), file, 266 strerror(ENOENT)); 267 return (0); 268 } 269 name = path; 270 } 271 if ((pnp = expand_paths(clmp, name, 272 PN_SER_NEEDED, 0)) == 0) 273 return (0); 274 } else { 275 /* 276 * If the library is specified as a pathname, see if 277 * it must be fixed to specify the current working 278 * directory (ie. libc.so.1.2 -> ./libc.so.1.2). 279 */ 280 if ((pnp = aout_fix_name(name, clmp)) == 0) 281 return (0); 282 } 283 284 DBG_CALL(Dbg_file_needed(clmp, name)); 285 286 nlmp = load_one(lml, lmco, pnp, clmp, MODE(clmp), 0, 0); 287 remove_pnode(pnp); 288 if (((nlmp == 0) || (bind_one(clmp, nlmp, BND_NEEDED) == 0)) && 289 ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0)) 290 return (0); 291 } 292 293 return (1); 294 } 295 296 static Sym * 297 aout_symconvert(struct nlist *sp) 298 { 299 static Sym sym; 300 301 sym.st_value = sp->n_value; 302 sym.st_size = 0; 303 sym.st_info = 0; 304 sym.st_other = 0; 305 switch (sp->n_type) { 306 case N_EXT + N_ABS: 307 sym.st_shndx = SHN_ABS; 308 break; 309 case N_COMM: 310 sym.st_shndx = SHN_COMMON; 311 break; 312 case N_EXT + N_UNDF: 313 sym.st_shndx = SHN_UNDEF; 314 break; 315 default: 316 sym.st_shndx = 0; 317 break; 318 } 319 return (&sym); 320 } 321 322 /* 323 * Process a.out format commons. 324 */ 325 static struct nlist * 326 aout_find_com(struct nlist *sp, const char *name) 327 { 328 static struct rtc_symb *rtcp = 0; 329 struct rtc_symb *rs, * trs; 330 const char *sl; 331 char *cp; 332 333 /* 334 * See if common is already allocated. 335 */ 336 trs = rtcp; 337 while (trs) { 338 sl = name; 339 cp = trs->rtc_sp->n_un.n_name; 340 while (*sl == *cp++) 341 if (*sl++ == '\0') 342 return (trs->rtc_sp); 343 trs = trs->rtc_next; 344 } 345 346 /* 347 * If we got here, common is not already allocated so allocate it. 348 */ 349 if ((rs = malloc(sizeof (struct rtc_symb))) == 0) 350 return (0); 351 if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == 0) 352 return (0); 353 trs = rtcp; 354 rtcp = rs; 355 rs->rtc_next = trs; 356 *(rs->rtc_sp) = *sp; 357 if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == 0) 358 return (0); 359 (void) strcpy(rs->rtc_sp->n_un.n_name, name); 360 rs->rtc_sp->n_type = N_COMM; 361 if ((rs->rtc_sp->n_value = (long)calloc(rs->rtc_sp->n_value, 1)) == 0) 362 return (0); 363 return (rs->rtc_sp); 364 } 365 366 /* 367 * Find a.out format symbol in the specified link map. Unlike the sister 368 * elf routine we re-calculate the symbols hash value for each link map 369 * we're looking at. 370 */ 371 static struct nlist * 372 aout_findsb(const char *aname, Rt_map *lmp, int flag) 373 { 374 const char *name = aname; 375 char *cp; 376 struct fshash *p; 377 int i; 378 struct nlist *sp; 379 ulong_t hval = 0; 380 381 #define HASHMASK 0x7fffffff 382 #define RTHS 126 383 384 /* 385 * The name passed to us is in ELF format, thus it is necessary to 386 * map this back to the A_OUT format to compute the hash value (see 387 * mapping rules in aout_lookup_sym()). Basically the symbols are 388 * mapped according to whether a leading `.' exists. 389 * 390 * elf symbol a.out symbol 391 * i. .bar -> .bar (LKUP_LDOT) 392 * ii. .nuts -> nuts 393 * iii. foo -> _foo 394 */ 395 if (*name == '.') { 396 if (!(flag & LKUP_LDOT)) 397 name++; 398 } else 399 hval = '_'; 400 401 while (*name) 402 hval = (hval << 1) + *name++; 403 hval = hval & HASHMASK; 404 405 i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS : 406 AOUTDYN(lmp)->v2->ld_buckets); 407 p = LM2LP(lmp)->lp_hash + i; 408 409 if (p->fssymbno != -1) 410 do { 411 sp = &LM2LP(lmp)->lp_symtab[p->fssymbno]; 412 cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; 413 name = aname; 414 if (*name == '.') { 415 if (!(flag & LKUP_LDOT)) 416 name++; 417 } else { 418 cp++; 419 } 420 while (*name == *cp++) { 421 if (*name++ == '\0') 422 return (sp); /* found */ 423 } 424 if (p->next == 0) 425 return (0); /* not found */ 426 else 427 continue; 428 } while ((p = &LM2LP(lmp)->lp_hash[p->next]) != 0); 429 return (0); 430 } 431 432 /* 433 * The symbol name we have been asked to look up is in A_OUT format, this 434 * symbol is mapped to the appropriate ELF format which is the standard by 435 * which symbols are passed around ld.so.1. The symbols are mapped 436 * according to whether a leading `_' or `.' exists. 437 * 438 * a.out symbol elf symbol 439 * i. _foo -> foo 440 * ii. .bar -> .bar (LKUP_LDOT) 441 * iii. nuts -> .nuts 442 */ 443 Sym * 444 aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo) 445 { 446 char name[PATH_MAX]; 447 Slookup sl = *slp; 448 449 DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_imap), slp->sl_name)); 450 451 if (*sl.sl_name == '_') 452 ++sl.sl_name; 453 else if (*sl.sl_name == '.') 454 sl.sl_flags |= LKUP_LDOT; 455 else { 456 name[0] = '.'; 457 (void) strcpy(&name[1], sl.sl_name); 458 sl.sl_name = name; 459 } 460 461 /* 462 * Call the generic lookup routine to cycle through the specified 463 * link maps. 464 */ 465 return (lookup_sym(&sl, dlmp, binfo)); 466 } 467 468 /* 469 * Symbol lookup for an a.out format module. 470 */ 471 static Sym * 472 aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo) 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 { 814 Sym *sym; 815 char buffer[PATH_MAX]; 816 Slookup sl; 817 818 buffer[0] = '_'; 819 (void) strcpy(&buffer[1], slp->sl_name); 820 821 if ((sym = dlsym_handle(ghp, slp, _lmp, binfo)) != 0) 822 return (sym); 823 824 /* 825 * Symbol not found as supplied. However, most of our symbols will 826 * be in the "C" name space, where the implementation prepends a "_" 827 * to the symbol as it emits it. Therefore, attempt to find the 828 * symbol with the "_" prepend. 829 */ 830 sl = *slp; 831 sl.sl_name = (const char *)buffer; 832 833 return (dlsym_handle(ghp, &sl, _lmp, binfo)); 834 } 835