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 2009 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/types.h> 35 #include <sys/procfs.h> 36 #include <sys/mman.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #include <string.h> 40 #include <limits.h> 41 #include <stdio.h> 42 #include <dlfcn.h> 43 #include <errno.h> 44 #include <debug.h> 45 #include "_a.out.h" 46 #include "cache_a.out.h" 47 #include "msg.h" 48 #include "_rtld.h" 49 50 /* 51 * Default and secure dependency search paths. 52 */ 53 static Spath_defn _aout_def_dirs[] = { 54 { MSG_ORIG(MSG_PTH_USR4LIB), MSG_PTH_USR4LIB_SIZE }, 55 { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE }, 56 { MSG_ORIG(MSG_PTH_USRLCLIB), MSG_PTH_USRLCLIB_SIZE }, 57 { 0, 0 } 58 }; 59 60 static Spath_defn _aout_sec_dirs[] = { 61 { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE }, 62 { 0, 0 } 63 }; 64 65 Alist *aout_def_dirs = NULL; 66 Alist *aout_sec_dirs = NULL; 67 68 /* 69 * Defines for local functions. 70 */ 71 static void aout_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int); 72 static Sym *aout_dlsym_handle(Grp_hdl *, Slookup *, Rt_map **, uint_t *, 73 int *l); 74 static Addr aout_entry_point(void); 75 static Sym *aout_find_sym(Slookup *, Rt_map **, uint_t *, int *); 76 static int aout_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t); 77 static Alist **aout_get_def_dirs(void); 78 static Alist **aout_get_sec_dirs(void); 79 static char *aout_get_so(const char *, const char *, size_t, size_t); 80 extern Sym *aout_lookup_sym(Slookup *, Rt_map **, uint_t *, int *); 81 static int aout_needed(Lm_list *, Aliste, Rt_map *, int *); 82 83 /* 84 * Functions and data accessed through indirect pointers. 85 */ 86 Fct aout_fct = { 87 aout_verify, 88 aout_new_lmp, 89 aout_entry_point, 90 aout_needed, 91 aout_lookup_sym, 92 aout_reloc, 93 aout_get_def_dirs, 94 aout_get_sec_dirs, 95 aout_fix_name, 96 aout_get_so, 97 aout_dladdr, 98 aout_dlsym_handle 99 }; 100 101 /* 102 * Default and secure dependency search paths. 103 */ 104 static Alist ** 105 aout_get_def_dirs() 106 { 107 if (aout_def_dirs == NULL) 108 set_dirs(&aout_def_dirs, _aout_def_dirs, LA_SER_DEFAULT); 109 return (&aout_def_dirs); 110 } 111 112 static Alist ** 113 aout_get_sec_dirs() 114 { 115 if (aout_sec_dirs == NULL) 116 set_dirs(&aout_sec_dirs, _aout_sec_dirs, LA_SER_SECURE); 117 return (&aout_sec_dirs); 118 } 119 120 /* 121 * In 4.x, a needed file or a dlopened file that was a simple file name implied 122 * that the file be found in the present working directory. To simulate this 123 * lookup within the ELF rules it is necessary to add a preceding `./' to the 124 * filename. 125 */ 126 /* ARGSUSED4 */ 127 static int 128 aout_fix_name(const char *oname, Rt_map *clmp, Alist **alpp, Aliste alni, 129 uint_t orig) 130 { 131 size_t len; 132 Pdesc *pdp; 133 const char *nname; 134 135 /* 136 * Check for slash in name, if none, prepend "./", otherwise just 137 * return name given. 138 */ 139 if (strchr(oname, '/')) { 140 len = strlen(oname) + 1; 141 if ((nname = stravl_insert(oname, 0, len, 0)) == NULL) 142 return (0); 143 } else { 144 char buffer[PATH_MAX]; 145 146 len = strlen(oname) + 3; 147 (void) snprintf(buffer, len, MSG_ORIG(MSG_FMT_4XPATH), oname); 148 if ((nname = stravl_insert(buffer, 0, len, 0)) == NULL) 149 return (0); 150 } 151 152 if ((pdp = alist_append(alpp, 0, sizeof (Pdesc), alni)) == NULL) 153 return (0); 154 155 pdp->pd_pname = nname; 156 pdp->pd_plen = len; 157 pdp->pd_flags = PD_FLG_PNSLASH; 158 159 DBG_CALL(Dbg_file_fixname(LIST(clmp), nname, oname)); 160 return (1); 161 } 162 163 /* 164 * Determine if we have been given an A_OUT file. Returns 1 if true. 165 */ 166 Fct * 167 /* ARGSUSED1 */ 168 aout_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name, 169 Rej_desc *rej) 170 { 171 /* LINTED */ 172 struct exec *exec = (struct exec *)addr; 173 174 if (size < sizeof (exec) || (exec->a_machtype != M_SPARC) || 175 (N_BADMAG(*exec))) { 176 return (NULL); 177 } 178 return (&aout_fct); 179 } 180 181 /* 182 * Return the entry point of the A_OUT executable. Although the entry point 183 * within an ELF file is flexible, the entry point of an A_OUT executable is 184 * always zero. 185 */ 186 static Addr 187 aout_entry_point() 188 { 189 return (0); 190 } 191 192 /* 193 * Search through the dynamic section for DT_NEEDED entries and perform one 194 * of two functions. If only the first argument is specified then load the 195 * defined shared object, otherwise add the link map representing the 196 * defined link map the the dlopen list. 197 */ 198 static int 199 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 200 { 201 Alist *palp = NULL; 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 210 name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name]; 211 212 if (((Lnk_obj *)(need))->lo_library) { 213 /* 214 * If lo_library field is not NULL then this needed 215 * library was linked in using the "-l" option. 216 * Thus we need to rebuild the library name before 217 * trying to load it. 218 */ 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)) == NULL) 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 Spath_desc sd = { search_rules, NULL, 0 }; 248 Pdesc *pdp; 249 char *path = NULL; 250 251 for (pdp = get_next_dir(&sd, clmp, 0); pdp; 252 pdp = get_next_dir(&sd, clmp, 0)) { 253 if (pdp->pd_pname == 0) 254 continue; 255 256 if (path = aout_get_so(pdp->pd_pname, 257 file, 0, 0)) 258 break; 259 } 260 if (path == NULL) { 261 eprintf(lml, ERR_FATAL, 262 MSG_INTL(MSG_SYS_OPEN), file, 263 strerror(ENOENT)); 264 return (0); 265 } 266 name = path; 267 } 268 if (expand_paths(clmp, name, &palp, 269 AL_CNT_NEEDED, 0, 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 (aout_fix_name(name, clmp, &palp, 278 AL_CNT_NEEDED, 0) == 0) 279 return (0); 280 } 281 282 DBG_CALL(Dbg_file_needed(clmp, name)); 283 284 nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 0, 0, 285 in_nfavl); 286 remove_plist(&palp, 1); 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))) == NULL) 349 return (NULL); 350 if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == NULL) 351 return (NULL); 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)) == NULL) 357 return (NULL); 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 = 361 (long)calloc(rs->rtc_sp->n_value, 1)) == NULL) 362 return (NULL); 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 (NULL); /* not found */ 426 else 427 continue; 428 } while ((p = &LM2LP(lmp)->lp_hash[p->next]) != 0); 429 } 430 return (NULL); 431 } 432 433 /* 434 * The symbol name we have been asked to look up is in A_OUT format, this 435 * symbol is mapped to the appropriate ELF format which is the standard by 436 * which symbols are passed around ld.so.1. The symbols are mapped 437 * according to whether a leading `_' or `.' exists. 438 * 439 * a.out symbol elf symbol 440 * i. _foo -> foo 441 * ii. .bar -> .bar (LKUP_LDOT) 442 * iii. nuts -> .nuts 443 */ 444 Sym * 445 aout_lookup_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 446 { 447 char name[PATH_MAX]; 448 Slookup sl = *slp; 449 450 DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_cmap), slp->sl_name)); 451 452 if (*sl.sl_name == '_') 453 ++sl.sl_name; 454 else if (*sl.sl_name == '.') 455 sl.sl_flags |= LKUP_LDOT; 456 else { 457 name[0] = '.'; 458 (void) strcpy(&name[1], sl.sl_name); 459 sl.sl_name = name; 460 } 461 462 /* 463 * Call the generic lookup routine to cycle through the specified 464 * link maps. 465 */ 466 return (lookup_sym(&sl, dlmp, binfo, in_nfavl)); 467 } 468 469 /* 470 * Symbol lookup for an a.out format module. 471 */ 472 /* ARGSUSED3 */ 473 static Sym * 474 aout_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 475 { 476 const char *name = slp->sl_name; 477 Rt_map *ilmp = slp->sl_imap; 478 struct nlist *sp; 479 480 DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_AOUT))); 481 482 if (sp = aout_findsb(name, ilmp, slp->sl_flags)) { 483 if (sp->n_value != 0) { 484 /* 485 * is it a common? 486 */ 487 if (sp->n_type == (N_EXT + N_UNDF)) { 488 if ((sp = aout_find_com(sp, name)) == 0) 489 return (NULL); 490 } 491 *dlmp = ilmp; 492 *binfo |= DBG_BINFO_FOUND; 493 return (aout_symconvert(sp)); 494 } 495 } 496 return (NULL); 497 } 498 499 /* 500 * Create a new Rt_map structure for an a.out format object and 501 * initializes all values. 502 */ 503 /* ARGSUSED6 */ 504 Rt_map * 505 aout_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, 506 void *odyn, int *in_nfavl) 507 { 508 const char *name = fdp->fd_nname; 509 Rt_map *lmp; 510 caddr_t base, caddr = (caddr_t)addr; 511 Link_dynamic *ld = (Link_dynamic *)odyn; 512 size_t lmsz, rtsz, prsz; 513 514 DBG_CALL(Dbg_file_aout(lml, name, addr, msize, lml->lm_lmidstr, lmco)); 515 516 /* 517 * Allocate space for the link-map and private a.out information. Once 518 * these are allocated and initialized, we can use remove_so(0, lmp) to 519 * tear down the link-map should any failures occur. 520 */ 521 rtsz = S_DROUND(sizeof (Rt_map)); 522 prsz = S_DROUND(sizeof (Rt_aoutp)); 523 lmsz = rtsz + prsz + sizeof (struct ld_private); 524 if ((lmp = calloc(lmsz, 1)) == NULL) 525 return (NULL); 526 AOUTPRV(lmp) = (void *)((uintptr_t)lmp + rtsz); 527 ((Rt_aoutp *)AOUTPRV(lmp))->lm_lpd = 528 (void *)((uintptr_t)lmp + rtsz + prsz); 529 LMSIZE(lmp) = lmsz; 530 531 /* 532 * All fields not filled in were set to 0 by calloc. 533 */ 534 NAME(lmp) = (char *)name; 535 ADDR(lmp) = addr; 536 MSIZE(lmp) = msize; 537 SYMINTP(lmp) = aout_find_sym; 538 FCT(lmp) = &aout_fct; 539 LIST(lmp) = lml; 540 OBJFLTRNDX(lmp) = FLTR_DISABLED; 541 SORTVAL(lmp) = -1; 542 543 /* 544 * Specific settings for a.out format. 545 */ 546 if (lml->lm_head == 0) { 547 base = (caddr_t)MAIN_BASE; 548 FLAGS(lmp) |= FLG_RT_FIXED; 549 } else 550 base = caddr; 551 552 /* 553 * Fill in all AOUT information. Applications provide the Link_dynamic 554 * offset via the boot block, but if this is a shared object that 555 * ld.so.1 has mapped, then determine the Link_dynamic offset from the 556 * mapped image. 557 */ 558 if (ld == NULL) { 559 /* LINTED */ 560 struct exec *exec = (struct exec *)caddr; 561 struct nlist *nl; 562 563 /* LINTED */ 564 nl = (struct nlist *)&caddr[N_SYMOFF(*exec)]; 565 /* LINTED */ 566 ld = (Link_dynamic *)&caddr[nl->n_value]; 567 568 ld->v2 = (struct link_dynamic_2 *)((int)ld->v2 + (int)caddr); 569 } 570 AOUTDYN(lmp) = ld; 571 572 if ((RPATH(lmp) = (char *)&base[ld->v2->ld_rules]) == base) 573 RPATH(lmp) = 0; 574 LM2LP(lmp)->lp_symbol_base = caddr; 575 /* LINTED */ 576 LM2LP(lmp)->lp_plt = (struct jbind *)(&caddr[JMPOFF(ld)]); 577 LM2LP(lmp)->lp_rp = 578 /* LINTED */ 579 (struct relocation_info *)(&base[RELOCOFF(ld)]); 580 /* LINTED */ 581 LM2LP(lmp)->lp_hash = (struct fshash *)(&base[HASHOFF(ld)]); 582 /* LINTED */ 583 LM2LP(lmp)->lp_symtab = (struct nlist *)(&base[SYMOFF(ld)]); 584 LM2LP(lmp)->lp_symstr = &base[STROFF(ld)]; 585 LM2LP(lmp)->lp_textbase = base; 586 LM2LP(lmp)->lp_refcnt++; 587 LM2LP(lmp)->lp_dlp = NULL; 588 589 /* 590 * Add the mapped object to the end of the link map list. 591 */ 592 lm_append(lml, lmco, lmp); 593 return (lmp); 594 } 595 596 /* 597 * Build full pathname of shared object from the given directory name and 598 * filename. 599 */ 600 static char * 601 /* ARGSUSED2 */ 602 aout_get_so(const char *dir, const char *file, size_t dlen, size_t flen) 603 { 604 struct db *dbp; 605 char *path = NULL; 606 607 if (dbp = lo_cache(dir)) { 608 path = ask_db(dbp, file); 609 } 610 return (path); 611 } 612 613 /* 614 * Determine the symbol location of an address within a link-map. Look for 615 * the nearest symbol (whoes value is less than or equal to the required 616 * address). This is the object specific part of dladdr(). 617 */ 618 static void 619 aout_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, 620 int flags) 621 { 622 ulong_t ndx, cnt, base, _value; 623 struct nlist *sym, *_sym; 624 625 cnt = ((int)LM2LP(lmp)->lp_symstr - (int)LM2LP(lmp)->lp_symtab) / 626 sizeof (struct nlist); 627 sym = LM2LP(lmp)->lp_symtab; 628 629 if (FLAGS(lmp) & FLG_RT_FIXED) 630 base = 0; 631 else 632 base = ADDR(lmp); 633 634 for (_sym = 0, _value = 0, ndx = 0; ndx < cnt; ndx++, sym++) { 635 ulong_t value; 636 637 if (sym->n_type == (N_EXT + N_UNDF)) 638 continue; 639 640 value = sym->n_value + base; 641 if (value > addr) 642 continue; 643 if (value < _value) 644 continue; 645 646 _sym = sym; 647 _value = value; 648 649 if (value == addr) 650 break; 651 } 652 653 if (_sym) { 654 int _flags = flags & RTLD_DL_MASK; 655 656 /* 657 * The only way we can create a symbol entry is to use 658 * aout_symconvert(), however this results in us pointing to 659 * static data that could be overridden. In addition the AOUT 660 * symbol format doesn't give us everything an ELF symbol does. 661 * So, unless we get convinced otherwise, don't bother returning 662 * a symbol entry for AOUT's. 663 */ 664 if (_flags == RTLD_DL_SYMENT) 665 *info = 0; 666 else if (_flags == RTLD_DL_LINKMAP) 667 *info = (void *)lmp; 668 669 dlip->dli_sname = &LM2LP(lmp)->lp_symstr[_sym->n_un.n_strx]; 670 dlip->dli_saddr = (void *)_value; 671 } 672 } 673 674 /* 675 * Continue processing a dlsym request. Lookup the required symbol in each 676 * link-map specified by the handle. Note, that because this lookup is against 677 * individual link-maps we don't need to supply a starting link-map to the 678 * lookup routine (see lookup_sym():analyze.c). 679 */ 680 static Sym * 681 aout_dlsym_handle(Grp_hdl *ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo, 682 int *in_nfavl) 683 { 684 Sym *sym; 685 char buffer[PATH_MAX]; 686 Slookup sl; 687 688 buffer[0] = '_'; 689 (void) strcpy(&buffer[1], slp->sl_name); 690 691 if ((sym = dlsym_handle(ghp, slp, _lmp, binfo, in_nfavl)) != 0) 692 return (sym); 693 694 /* 695 * Symbol not found as supplied. However, most of our symbols will 696 * be in the "C" name space, where the implementation prepends a "_" 697 * to the symbol as it emits it. Therefore, attempt to find the 698 * symbol with the "_" prepend. 699 */ 700 sl = *slp; 701 sl.sl_name = (const char *)buffer; 702 703 return (dlsym_handle(ghp, &sl, _lmp, binfo, in_nfavl)); 704 } 705 706 /* 707 * The initial mapping of the a.out occurs through exec(2), and presently this 708 * implementation doesn't provide a mmapobj_result_t array to ld.so.1. Thus, 709 * aout_get_mmap() is called to create the mapping information. Unlike ELF, 710 * the information that can be gathered from a mapped AOUT file, can be limited. 711 * In some cases the AOUT header isn't available in the mapped image, and thus 712 * this can't be inspected to determine the files size (the kernel always 713 * returns a pointer to the AOUT dynamic structure, but this is only sufficient 714 * to determine the size of the text segment). 715 * 716 * Therefore, the only generic mechanism of determining the AOUT's mapping is 717 * to use /proc. Only two mappings are required, the text (to determine any 718 * read-only region), and the data. The two mapping validate the range in 719 * which any relocations will occur. Should there be an additional bss segment, 720 * we don't care, as this can't be relocated, and we're never going to try 721 * unmapping the a.out. 722 */ 723 int 724 aout_get_mmap(Lm_list *lml, mmapobj_result_t *mpp) 725 { 726 prmap_t *maps; 727 char proc[16]; 728 int num, err, fd; 729 730 (void) snprintf(proc, 16, MSG_ORIG(MSG_FMT_PROC), (int)getpid()); 731 if ((fd = open(proc, O_RDONLY)) == -1) { 732 err = errno; 733 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc, 734 strerror(err)); 735 return (1); 736 } 737 738 if (ioctl(fd, PIOCNMAP, (void *)&num) == -1) { 739 err = errno; 740 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err)); 741 return (1); 742 } 743 744 if ((maps = malloc((num + 1) * sizeof (prmap_t))) == NULL) 745 return (1); 746 747 if (ioctl(fd, PIOCMAP, (void *)maps) == -1) { 748 err = errno; 749 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err)); 750 free(maps); 751 return (1); 752 } 753 754 mpp->mr_addr = maps->pr_vaddr; 755 mpp->mr_fsize = mpp->mr_msize = maps->pr_size; 756 mpp->mr_prot = (PROT_READ | PROT_EXEC); 757 758 mpp++, maps++; 759 760 mpp->mr_addr = maps->pr_vaddr; 761 mpp->mr_fsize = mpp->mr_msize = maps->pr_size; 762 mpp->mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC); 763 764 maps--; 765 free(maps); 766 return (0); 767 } 768