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 (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26/* 27 * Object file dependent support for a.out format objects. 28 */ 29 30#include <a.out.h> /* Explicitly override M_SEGSIZE */ 31#include <machdep.h> /* used in M_SROUND */ 32 33#include <sys/types.h> 34#include <sys/procfs.h> 35#include <sys/mman.h> 36#include <fcntl.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 */ 52static Spath_defn _aout_def_dirs[] = { 53 { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE }, 54 { MSG_ORIG(MSG_PTH_USRLCLIB), MSG_PTH_USRLCLIB_SIZE }, 55 { 0, 0 } 56}; 57 58static Spath_defn _aout_sec_dirs[] = { 59 { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE }, 60 { 0, 0 } 61}; 62 63Alist *aout_def_dirs = NULL; 64Alist *aout_sec_dirs = NULL; 65 66/* 67 * Defines for local functions. 68 */ 69static void aout_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int); 70static int aout_dlsym_handle(Grp_hdl *, Slookup *, Sresult *, uint_t *, 71 int *); 72static Addr aout_entry_point(void); 73static int aout_find_sym(Slookup *, Sresult *, uint_t *, int *); 74static int aout_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t); 75static Alist **aout_get_def_dirs(void); 76static Alist **aout_get_sec_dirs(void); 77static char *aout_get_so(const char *, const char *, size_t, size_t); 78static int aout_needed(Lm_list *, Aliste, Rt_map *, int *); 79 80/* 81 * Functions and data accessed through indirect pointers. 82 */ 83Fct aout_fct = { 84 aout_verify, 85 aout_new_lmp, 86 aout_entry_point, 87 aout_needed, 88 aout_lookup_sym, 89 aout_reloc, 90 aout_get_def_dirs, 91 aout_get_sec_dirs, 92 aout_fix_name, 93 aout_get_so, 94 aout_dladdr, 95 aout_dlsym_handle 96}; 97 98/* 99 * Default and secure dependency search paths. 100 */ 101static Alist ** 102aout_get_def_dirs() 103{ 104 if (aout_def_dirs == NULL) 105 set_dirs(&aout_def_dirs, _aout_def_dirs, LA_SER_DEFAULT); 106 return (&aout_def_dirs); 107} 108 109static Alist ** 110aout_get_sec_dirs() 111{ 112 if (aout_sec_dirs == NULL) 113 set_dirs(&aout_sec_dirs, _aout_sec_dirs, LA_SER_SECURE); 114 return (&aout_sec_dirs); 115} 116 117/* 118 * In 4.x, a needed file or a dlopened file that was a simple file name implied 119 * that the file be found in the present working directory. To simulate this 120 * lookup within the ELF rules it is necessary to add a preceding `./' to the 121 * filename. 122 */ 123/* ARGSUSED4 */ 124static int 125aout_fix_name(const char *oname, Rt_map *clmp, Alist **alpp, Aliste alni, 126 uint_t orig) 127{ 128 size_t len; 129 Pdesc *pdp; 130 const char *nname; 131 132 /* 133 * Check for slash in name, if none, prepend "./", otherwise just 134 * return name given. 135 */ 136 if (strchr(oname, '/')) { 137 len = strlen(oname) + 1; 138 if ((nname = stravl_insert(oname, 0, len, 0)) == NULL) 139 return (0); 140 } else { 141 char buffer[PATH_MAX]; 142 143 len = strlen(oname) + 3; 144 (void) snprintf(buffer, len, MSG_ORIG(MSG_FMT_4XPATH), oname); 145 if ((nname = stravl_insert(buffer, 0, len, 0)) == NULL) 146 return (0); 147 } 148 149 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), alni)) == NULL) 150 return (0); 151 152 pdp->pd_pname = nname; 153 pdp->pd_plen = len; 154 pdp->pd_flags = PD_FLG_PNSLASH; 155 156 DBG_CALL(Dbg_file_fixname(LIST(clmp), nname, oname)); 157 return (1); 158} 159 160/* 161 * Determine if we have been given an A_OUT file. Returns 1 if true. 162 */ 163Fct * 164/* ARGSUSED1 */ 165aout_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name, 166 Rej_desc *rej) 167{ 168 /* LINTED */ 169 struct exec *exec = (struct exec *)addr; 170 171 if (size < sizeof (exec) || (exec->a_machtype != M_SPARC) || 172 (N_BADMAG(*exec))) { 173 return (NULL); 174 } 175 return (&aout_fct); 176} 177 178/* 179 * Return the entry point of the A_OUT executable. Although the entry point 180 * within an ELF file is flexible, the entry point of an A_OUT executable is 181 * always zero. 182 */ 183static Addr 184aout_entry_point() 185{ 186 return (0); 187} 188 189/* 190 * Search through the dynamic section for DT_NEEDED entries and perform one 191 * of two functions. If only the first argument is specified then load the 192 * defined shared object, otherwise add the link map representing the 193 * defined link map the the dlopen list. 194 */ 195static int 196aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 197{ 198 Alist *palp = NULL; 199 void *need; 200 201 for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need]; 202 need != &TEXTBASE(clmp)[0]; 203 need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) { 204 Rt_map *nlmp; 205 char *name; 206 207 name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name]; 208 209 if (((Lnk_obj *)(need))->lo_library) { 210 /* 211 * If lo_library field is not NULL then this needed 212 * library was linked in using the "-l" option. 213 * Thus we need to rebuild the library name before 214 * trying to load it. 215 */ 216 char *file; 217 size_t len; 218 219 /* 220 * Allocate name length plus 20 for full library name. 221 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20 222 */ 223 len = strlen(name) + 20; 224 if ((file = malloc(len)) == NULL) 225 return (0); 226 (void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB), 227 name, ((Lnk_obj *)(need))->lo_major, 228 ((Lnk_obj *)(need))->lo_minor); 229 230 DBG_CALL(Dbg_libs_find(lml, file)); 231 232 /* 233 * We need to determine what filename will match the 234 * the filename specified (ie, a libc.so.1.2 may match 235 * to a libc.so.1.3). It's the real pathname that is 236 * recorded in the link maps. If we are presently 237 * being traced, skip this pathname generation so 238 * that we fall through into load_so() to print the 239 * appropriate diagnostics. I don't like this at all. 240 */ 241 if (lml->lm_flags & LML_FLG_TRC_ENABLE) 242 name = file; 243 else { 244 Spath_desc sd = { search_rules, NULL, 0 }; 245 Pdesc *pdp; 246 char *path = NULL; 247 248 for (pdp = get_next_dir(&sd, clmp, 0); pdp; 249 pdp = get_next_dir(&sd, clmp, 0)) { 250 if (pdp->pd_pname == NULL) 251 continue; 252 253 if (path = aout_get_so(pdp->pd_pname, 254 file, 0, 0)) 255 break; 256 } 257 if (path == NULL) { 258 eprintf(lml, ERR_FATAL, 259 MSG_INTL(MSG_SYS_OPEN), file, 260 strerror(ENOENT)); 261 return (0); 262 } 263 name = path; 264 } 265 if (expand_paths(clmp, name, &palp, 266 AL_CNT_NEEDED, 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 (aout_fix_name(name, clmp, &palp, 275 AL_CNT_NEEDED, 0) == 0) 276 return (0); 277 } 278 279 DBG_CALL(Dbg_file_needed(clmp, name)); 280 281 nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 0, 0, 282 in_nfavl); 283 remove_alist(&palp, 1); 284 if (((nlmp == NULL) || 285 (bind_one(clmp, nlmp, BND_NEEDED) == 0)) && 286 ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0)) 287 return (0); 288 } 289 290 return (1); 291} 292 293static Sym * 294aout_symconvert(struct nlist *sp) 295{ 296 static Sym sym; 297 298 sym.st_value = sp->n_value; 299 sym.st_size = 0; 300 sym.st_info = 0; 301 sym.st_other = 0; 302 switch (sp->n_type) { 303 case N_EXT + N_ABS: 304 sym.st_shndx = SHN_ABS; 305 break; 306 case N_COMM: 307 sym.st_shndx = SHN_COMMON; 308 break; 309 case N_EXT + N_UNDF: 310 sym.st_shndx = SHN_UNDEF; 311 break; 312 default: 313 sym.st_shndx = 0; 314 break; 315 } 316 return (&sym); 317} 318 319/* 320 * Process a.out format commons. 321 */ 322static struct nlist * 323aout_find_com(struct nlist *sp, const char *name) 324{ 325 static struct rtc_symb *rtcp = NULL; 326 struct rtc_symb *rs, *trs; 327 const char *sl; 328 char *cp; 329 330 /* 331 * See if common is already allocated. 332 */ 333 trs = rtcp; 334 while (trs) { 335 sl = name; 336 cp = trs->rtc_sp->n_un.n_name; 337 while (*sl == *cp++) 338 if (*sl++ == '\0') 339 return (trs->rtc_sp); 340 trs = trs->rtc_next; 341 } 342 343 /* 344 * If we got here, common is not already allocated so allocate it. 345 */ 346 if ((rs = malloc(sizeof (struct rtc_symb))) == NULL) 347 return (NULL); 348 if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == NULL) 349 return (NULL); 350 trs = rtcp; 351 rtcp = rs; 352 rs->rtc_next = trs; 353 *(rs->rtc_sp) = *sp; 354 if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == NULL) 355 return (NULL); 356 (void) strcpy(rs->rtc_sp->n_un.n_name, name); 357 rs->rtc_sp->n_type = N_COMM; 358 if ((rs->rtc_sp->n_value = 359 (long)calloc(rs->rtc_sp->n_value, 1)) == (long)NULL) 360 return (NULL); 361 return (rs->rtc_sp); 362} 363 364/* 365 * Find a.out format symbol in the specified link map. Unlike the sister 366 * elf routine we re-calculate the symbols hash value for each link map 367 * we're looking at. 368 */ 369static struct nlist * 370aout_findsb(const char *aname, Rt_map *lmp, int flag) 371{ 372 const char *name = aname; 373 char *cp; 374 struct fshash *p; 375 int i; 376 struct nlist *sp; 377 ulong_t hval = 0; 378 379#define HASHMASK 0x7fffffff 380#define RTHS 126 381 382 /* 383 * The name passed to us is in ELF format, thus it is necessary to 384 * map this back to the A_OUT format to compute the hash value (see 385 * mapping rules in aout_lookup_sym()). Basically the symbols are 386 * mapped according to whether a leading `.' exists. 387 * 388 * elf symbol a.out symbol 389 * i. .bar -> .bar (LKUP_LDOT) 390 * ii. .nuts -> nuts 391 * iii. foo -> _foo 392 */ 393 if (*name == '.') { 394 if (!(flag & LKUP_LDOT)) 395 name++; 396 } else 397 hval = '_'; 398 399 while (*name) 400 hval = (hval << 1) + *name++; 401 hval = hval & HASHMASK; 402 403 i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS : 404 AOUTDYN(lmp)->v2->ld_buckets); 405 p = LM2LP(lmp)->lp_hash + i; 406 407 if (p->fssymbno != -1) { 408 do { 409 sp = &LM2LP(lmp)->lp_symtab[p->fssymbno]; 410 cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; 411 name = aname; 412 if (*name == '.') { 413 if (!(flag & LKUP_LDOT)) 414 name++; 415 } else { 416 cp++; 417 } 418 while (*name == *cp++) { 419 if (*name++ == '\0') 420 return (sp); /* found */ 421 } 422 if (p->next == 0) 423 return (NULL); /* not found */ 424 else 425 continue; 426 } while ((p = &LM2LP(lmp)->lp_hash[p->next]) != NULL); 427 } 428 return (NULL); 429} 430 431/* 432 * The symbol name we have been asked to look up is in A_OUT format, this 433 * symbol is mapped to the appropriate ELF format which is the standard by 434 * which symbols are passed around ld.so.1. The symbols are mapped 435 * according to whether a leading `_' or `.' exists. 436 * 437 * a.out symbol elf symbol 438 * i. _foo -> foo 439 * ii. .bar -> .bar (LKUP_LDOT) 440 * iii. nuts -> .nuts 441 */ 442int 443aout_lookup_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl) 444{ 445 char name[PATH_MAX]; 446 Slookup sl = *slp; 447 448 DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_cmap), slp->sl_name)); 449 450 if (*sl.sl_name == '_') 451 ++sl.sl_name; 452 else if (*sl.sl_name == '.') 453 sl.sl_flags |= LKUP_LDOT; 454 else { 455 name[0] = '.'; 456 (void) strcpy(&name[1], sl.sl_name); 457 sl.sl_name = name; 458 } 459 460 /* 461 * Call the generic lookup routine to cycle through the specified 462 * link maps. 463 */ 464 return (lookup_sym(&sl, srp, binfo, in_nfavl)); 465} 466 467/* 468 * Symbol lookup for an a.out format module. 469 */ 470/* ARGSUSED3 */ 471static int 472aout_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl) 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)) == NULL) 487 return (0); 488 } 489 srp->sr_dmap = ilmp; 490 srp->sr_sym = aout_symconvert(sp); 491 *binfo |= DBG_BINFO_FOUND; 492 return (1); 493 } 494 } 495 return (0); 496} 497 498/* 499 * Create a new Rt_map structure for an a.out format object and 500 * initializes all values. 501 */ 502/* ARGSUSED6 */ 503Rt_map * 504aout_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, 505 void *odyn, Rt_map *clmp, int *in_nfavl) 506{ 507 const char *name = fdp->fd_nname; 508 Rt_map *lmp; 509 caddr_t base, caddr = (caddr_t)addr; 510 Link_dynamic *ld = (Link_dynamic *)odyn; 511 size_t lmsz, rtsz, prsz; 512 513 DBG_CALL(Dbg_file_aout(lml, name, addr, msize, lml->lm_lmidstr, lmco)); 514 515 /* 516 * Allocate space for the link-map and private a.out information. Once 517 * these are allocated and initialized, we can use remove_so(0, lmp) to 518 * tear down the link-map should any failures occur. 519 */ 520 rtsz = S_DROUND(sizeof (Rt_map)); 521 prsz = S_DROUND(sizeof (Rt_aoutp)); 522 lmsz = rtsz + prsz + sizeof (struct ld_private); 523 if ((lmp = calloc(lmsz, 1)) == NULL) 524 return (NULL); 525 AOUTPRV(lmp) = (void *)((uintptr_t)lmp + rtsz); 526 ((Rt_aoutp *)AOUTPRV(lmp))->lm_lpd = 527 (void *)((uintptr_t)lmp + rtsz + prsz); 528 LMSIZE(lmp) = lmsz; 529 530 /* 531 * All fields not filled in were set to 0 by calloc. 532 */ 533 NAME(lmp) = (char *)name; 534 ADDR(lmp) = addr; 535 MSIZE(lmp) = msize; 536 SYMINTP(lmp) = aout_find_sym; 537 FCT(lmp) = &aout_fct; 538 LIST(lmp) = lml; 539 OBJFLTRNDX(lmp) = FLTR_DISABLED; 540 SORTVAL(lmp) = -1; 541 542 /* 543 * Specific settings for a.out format. 544 */ 545 if (lml->lm_head == NULL) { 546 base = (caddr_t)MAIN_BASE; 547 FLAGS(lmp) |= FLG_RT_FIXED; 548 } else 549 base = caddr; 550 551 /* 552 * Fill in all AOUT information. Applications provide the Link_dynamic 553 * offset via the boot block, but if this is a shared object that 554 * ld.so.1 has mapped, then determine the Link_dynamic offset from the 555 * mapped image. 556 */ 557 if (ld == NULL) { 558 /* LINTED */ 559 struct exec *exec = (struct exec *)caddr; 560 struct nlist *nl; 561 562 /* LINTED */ 563 nl = (struct nlist *)&caddr[N_SYMOFF(*exec)]; 564 /* LINTED */ 565 ld = (Link_dynamic *)&caddr[nl->n_value]; 566 567 ld->v2 = (struct link_dynamic_2 *)((int)ld->v2 + (int)caddr); 568 } 569 AOUTDYN(lmp) = ld; 570 571 if ((RPATH(lmp) = (char *)&base[ld->v2->ld_rules]) == base) 572 RPATH(lmp) = NULL; 573 LM2LP(lmp)->lp_symbol_base = caddr; 574 /* LINTED */ 575 LM2LP(lmp)->lp_plt = (struct jbind *)(&caddr[JMPOFF(ld)]); 576 LM2LP(lmp)->lp_rp = 577 /* LINTED */ 578 (struct relocation_info *)(&base[RELOCOFF(ld)]); 579 /* LINTED */ 580 LM2LP(lmp)->lp_hash = (struct fshash *)(&base[HASHOFF(ld)]); 581 /* LINTED */ 582 LM2LP(lmp)->lp_symtab = (struct nlist *)(&base[SYMOFF(ld)]); 583 LM2LP(lmp)->lp_symstr = &base[STROFF(ld)]; 584 LM2LP(lmp)->lp_textbase = base; 585 LM2LP(lmp)->lp_refcnt++; 586 LM2LP(lmp)->lp_dlp = NULL; 587 588 /* 589 * Add the mapped object to the end of the link map list. 590 */ 591 lm_append(lml, lmco, lmp); 592 return (lmp); 593} 594 595/* 596 * Build full pathname of shared object from the given directory name and 597 * filename. 598 */ 599static char * 600/* ARGSUSED2 */ 601aout_get_so(const char *dir, const char *file, size_t dlen, size_t flen) 602{ 603 struct db *dbp; 604 char *path = NULL; 605 606 if (dbp = lo_cache(dir)) { 607 path = ask_db(dbp, file); 608 } 609 return (path); 610} 611 612/* 613 * Determine the symbol location of an address within a link-map. Look for 614 * the nearest symbol (whoes value is less than or equal to the required 615 * address). This is the object specific part of dladdr(). 616 */ 617static void 618aout_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, 619 int flags) 620{ 621 ulong_t ndx, cnt, base, _value; 622 struct nlist *sym, *_sym; 623 624 cnt = ((int)LM2LP(lmp)->lp_symstr - (int)LM2LP(lmp)->lp_symtab) / 625 sizeof (struct nlist); 626 sym = LM2LP(lmp)->lp_symtab; 627 628 if (FLAGS(lmp) & FLG_RT_FIXED) 629 base = 0; 630 else 631 base = ADDR(lmp); 632 633 for (_sym = NULL, _value = 0, ndx = 0; ndx < cnt; ndx++, sym++) { 634 ulong_t value; 635 636 if (sym->n_type == (N_EXT + N_UNDF)) 637 continue; 638 639 value = sym->n_value + base; 640 if (value > addr) 641 continue; 642 if (value < _value) 643 continue; 644 645 _sym = sym; 646 _value = value; 647 648 if (value == addr) 649 break; 650 } 651 652 if (_sym) { 653 int _flags = flags & RTLD_DL_MASK; 654 655 /* 656 * The only way we can create a symbol entry is to use 657 * aout_symconvert(), however this results in us pointing to 658 * static data that could be overridden. In addition the AOUT 659 * symbol format doesn't give us everything an ELF symbol does. 660 * So, unless we get convinced otherwise, don't bother returning 661 * a symbol entry for AOUT's. 662 */ 663 if (_flags == RTLD_DL_SYMENT) 664 *info = NULL; 665 else if (_flags == RTLD_DL_LINKMAP) 666 *info = (void *)lmp; 667 668 dlip->dli_sname = &LM2LP(lmp)->lp_symstr[_sym->n_un.n_strx]; 669 dlip->dli_saddr = (void *)_value; 670 } 671} 672 673/* 674 * Continue processing a dlsym request. Lookup the required symbol in each 675 * link-map specified by the handle. Note, that because this lookup is against 676 * individual link-maps we don't need to supply a starting link-map to the 677 * lookup routine (see lookup_sym():analyze.c). 678 */ 679static int 680aout_dlsym_handle(Grp_hdl *ghp, Slookup *slp, Sresult *srp, uint_t *binfo, 681 int *in_nfavl) 682{ 683 char buffer[PATH_MAX]; 684 Slookup sl; 685 686 if (dlsym_handle(ghp, slp, srp, binfo, in_nfavl)) 687 return (1); 688 689 /* 690 * Symbol not found as supplied. However, most of our symbols will 691 * be in the "C" name space, where the implementation prepends a "_" 692 * to the symbol as it emits it. Therefore, attempt to find the 693 * symbol with the "_" prepend. 694 */ 695 buffer[0] = '_'; 696 (void) strcpy(&buffer[1], slp->sl_name); 697 698 sl = *slp; 699 sl.sl_name = (const char *)buffer; 700 701 return (dlsym_handle(ghp, &sl, srp, binfo, in_nfavl)); 702} 703 704/* 705 * The initial mapping of the a.out occurs through exec(2), and presently this 706 * implementation doesn't provide a mmapobj_result_t array to ld.so.1. Thus, 707 * aout_get_mmap() is called to create the mapping information. Unlike ELF, 708 * the information that can be gathered from a mapped AOUT file, can be limited. 709 * In some cases the AOUT header isn't available in the mapped image, and thus 710 * this can't be inspected to determine the files size (the kernel always 711 * returns a pointer to the AOUT dynamic structure, but this is only sufficient 712 * to determine the size of the text segment). 713 * 714 * Therefore, the only generic mechanism of determining the AOUT's mapping is 715 * to use /proc. Only two mappings are required, the text (to determine any 716 * read-only region), and the data. The two mapping validate the range in 717 * which any relocations will occur. Should there be an additional bss segment, 718 * we don't care, as this can't be relocated, and we're never going to try 719 * unmapping the a.out. 720 */ 721#define PROCSIZE 20 722 723int 724aout_get_mmap(Lm_list *lml, mmapobj_result_t *mpp) 725{ 726 prmap_t *maps; 727 char proc[PROCSIZE]; 728 int num, err, fd; 729 730 (void) snprintf(proc, PROCSIZE, MSG_ORIG(MSG_FMT_PROC), 731 EC_SWORD(getpid())); 732 if ((fd = open(proc, O_RDONLY)) == -1) { 733 err = errno; 734 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc, 735 strerror(err)); 736 return (1); 737 } 738 739 if (ioctl(fd, PIOCNMAP, (void *)&num) == -1) { 740 err = errno; 741 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err)); 742 return (1); 743 } 744 745 if ((maps = malloc((num + 1) * sizeof (prmap_t))) == NULL) 746 return (1); 747 748 if (ioctl(fd, PIOCMAP, (void *)maps) == -1) { 749 err = errno; 750 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err)); 751 free(maps); 752 return (1); 753 } 754 755 mpp->mr_addr = maps->pr_vaddr; 756 mpp->mr_fsize = mpp->mr_msize = maps->pr_size; 757 mpp->mr_prot = (PROT_READ | PROT_EXEC); 758 759 mpp++, maps++; 760 761 mpp->mr_addr = maps->pr_vaddr; 762 mpp->mr_fsize = mpp->mr_msize = maps->pr_size; 763 mpp->mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC); 764 765 maps--; 766 free(maps); 767 return (0); 768} 769