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 */
52 static Spath_defn _aout_def_dirs[] = {
53 { MSG_ORIG(MSG_PTH_USR4LIB), MSG_PTH_USR4LIB_SIZE },
54 { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE },
55 { MSG_ORIG(MSG_PTH_USRLCLIB), MSG_PTH_USRLCLIB_SIZE },
56 { 0, 0 }
57 };
58
59 static Spath_defn _aout_sec_dirs[] = {
60 { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE },
61 { 0, 0 }
62 };
63
64 Alist *aout_def_dirs = NULL;
65 Alist *aout_sec_dirs = NULL;
66
67 /*
68 * Defines for local functions.
69 */
70 static void aout_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int);
71 static int aout_dlsym_handle(Grp_hdl *, Slookup *, Sresult *, uint_t *,
72 int *);
73 static Addr aout_entry_point(void);
74 static int aout_find_sym(Slookup *, Sresult *, uint_t *, int *);
75 static int aout_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t);
76 static Alist **aout_get_def_dirs(void);
77 static Alist **aout_get_sec_dirs(void);
78 static char *aout_get_so(const char *, const char *, size_t, size_t);
79 static int aout_needed(Lm_list *, Aliste, Rt_map *, int *);
80
81 /*
82 * Functions and data accessed through indirect pointers.
83 */
84 Fct aout_fct = {
85 aout_verify,
86 aout_new_lmp,
87 aout_entry_point,
88 aout_needed,
89 aout_lookup_sym,
90 aout_reloc,
91 aout_get_def_dirs,
92 aout_get_sec_dirs,
93 aout_fix_name,
94 aout_get_so,
95 aout_dladdr,
96 aout_dlsym_handle
97 };
98
99 /*
100 * Default and secure dependency search paths.
101 */
102 static Alist **
aout_get_def_dirs()103 aout_get_def_dirs()
104 {
105 if (aout_def_dirs == NULL)
106 set_dirs(&aout_def_dirs, _aout_def_dirs, LA_SER_DEFAULT);
107 return (&aout_def_dirs);
108 }
109
110 static Alist **
aout_get_sec_dirs()111 aout_get_sec_dirs()
112 {
113 if (aout_sec_dirs == NULL)
114 set_dirs(&aout_sec_dirs, _aout_sec_dirs, LA_SER_SECURE);
115 return (&aout_sec_dirs);
116 }
117
118 /*
119 * In 4.x, a needed file or a dlopened file that was a simple file name implied
120 * that the file be found in the present working directory. To simulate this
121 * lookup within the ELF rules it is necessary to add a preceding `./' to the
122 * filename.
123 */
124 /* ARGSUSED4 */
125 static int
aout_fix_name(const char * oname,Rt_map * clmp,Alist ** alpp,Aliste alni,uint_t orig)126 aout_fix_name(const char *oname, Rt_map *clmp, Alist **alpp, Aliste alni,
127 uint_t orig)
128 {
129 size_t len;
130 Pdesc *pdp;
131 const char *nname;
132
133 /*
134 * Check for slash in name, if none, prepend "./", otherwise just
135 * return name given.
136 */
137 if (strchr(oname, '/')) {
138 len = strlen(oname) + 1;
139 if ((nname = stravl_insert(oname, 0, len, 0)) == NULL)
140 return (0);
141 } else {
142 char buffer[PATH_MAX];
143
144 len = strlen(oname) + 3;
145 (void) snprintf(buffer, len, MSG_ORIG(MSG_FMT_4XPATH), oname);
146 if ((nname = stravl_insert(buffer, 0, len, 0)) == NULL)
147 return (0);
148 }
149
150 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), alni)) == NULL)
151 return (0);
152
153 pdp->pd_pname = nname;
154 pdp->pd_plen = len;
155 pdp->pd_flags = PD_FLG_PNSLASH;
156
157 DBG_CALL(Dbg_file_fixname(LIST(clmp), nname, oname));
158 return (1);
159 }
160
161 /*
162 * Determine if we have been given an A_OUT file. Returns 1 if true.
163 */
164 Fct *
165 /* ARGSUSED1 */
aout_verify(caddr_t addr,size_t size,Fdesc * fdp,const char * name,Rej_desc * rej)166 aout_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name,
167 Rej_desc *rej)
168 {
169 /* LINTED */
170 struct exec *exec = (struct exec *)addr;
171
172 if (size < sizeof (exec) || (exec->a_machtype != M_SPARC) ||
173 (N_BADMAG(*exec))) {
174 return (NULL);
175 }
176 return (&aout_fct);
177 }
178
179 /*
180 * Return the entry point of the A_OUT executable. Although the entry point
181 * within an ELF file is flexible, the entry point of an A_OUT executable is
182 * always zero.
183 */
184 static Addr
aout_entry_point()185 aout_entry_point()
186 {
187 return (0);
188 }
189
190 /*
191 * Search through the dynamic section for DT_NEEDED entries and perform one
192 * of two functions. If only the first argument is specified then load the
193 * defined shared object, otherwise add the link map representing the
194 * defined link map the the dlopen list.
195 */
196 static int
aout_needed(Lm_list * lml,Aliste lmco,Rt_map * clmp,int * in_nfavl)197 aout_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl)
198 {
199 Alist *palp = NULL;
200 void *need;
201
202 for (need = &TEXTBASE(clmp)[AOUTDYN(clmp)->v2->ld_need];
203 need != &TEXTBASE(clmp)[0];
204 need = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_next]) {
205 Rt_map *nlmp;
206 char *name;
207
208 name = &TEXTBASE(clmp)[((Lnk_obj *)(need))->lo_name];
209
210 if (((Lnk_obj *)(need))->lo_library) {
211 /*
212 * If lo_library field is not NULL then this needed
213 * library was linked in using the "-l" option.
214 * Thus we need to rebuild the library name before
215 * trying to load it.
216 */
217 char *file;
218 size_t len;
219
220 /*
221 * Allocate name length plus 20 for full library name.
222 * lib.so.. = 7 + (2 * short) + NULL = 7 + 12 + 1 = 20
223 */
224 len = strlen(name) + 20;
225 if ((file = malloc(len)) == NULL)
226 return (0);
227 (void) snprintf(file, len, MSG_ORIG(MSG_FMT_4XLIB),
228 name, ((Lnk_obj *)(need))->lo_major,
229 ((Lnk_obj *)(need))->lo_minor);
230
231 DBG_CALL(Dbg_libs_find(lml, file));
232
233 /*
234 * We need to determine what filename will match the
235 * the filename specified (ie, a libc.so.1.2 may match
236 * to a libc.so.1.3). It's the real pathname that is
237 * recorded in the link maps. If we are presently
238 * being traced, skip this pathname generation so
239 * that we fall through into load_so() to print the
240 * appropriate diagnostics. I don't like this at all.
241 */
242 if (lml->lm_flags & LML_FLG_TRC_ENABLE)
243 name = file;
244 else {
245 Spath_desc sd = { search_rules, NULL, 0 };
246 Pdesc *pdp;
247 char *path = NULL;
248
249 for (pdp = get_next_dir(&sd, clmp, 0); pdp;
250 pdp = get_next_dir(&sd, clmp, 0)) {
251 if (pdp->pd_pname == NULL)
252 continue;
253
254 if (path = aout_get_so(pdp->pd_pname,
255 file, 0, 0))
256 break;
257 }
258 if (path == NULL) {
259 eprintf(lml, ERR_FATAL,
260 MSG_INTL(MSG_SYS_OPEN), file,
261 strerror(ENOENT));
262 return (0);
263 }
264 name = path;
265 }
266 if (expand_paths(clmp, name, &palp,
267 AL_CNT_NEEDED, 0, 0) == 0)
268 return (0);
269 } else {
270 /*
271 * If the library is specified as a pathname, see if
272 * it must be fixed to specify the current working
273 * directory (ie. libc.so.1.2 -> ./libc.so.1.2).
274 */
275 if (aout_fix_name(name, clmp, &palp,
276 AL_CNT_NEEDED, 0) == 0)
277 return (0);
278 }
279
280 DBG_CALL(Dbg_file_needed(clmp, name));
281
282 nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 0, 0,
283 in_nfavl);
284 remove_alist(&palp, 1);
285 if (((nlmp == NULL) ||
286 (bind_one(clmp, nlmp, BND_NEEDED) == 0)) &&
287 ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0))
288 return (0);
289 }
290
291 return (1);
292 }
293
294 static Sym *
aout_symconvert(struct nlist * sp)295 aout_symconvert(struct nlist *sp)
296 {
297 static Sym sym;
298
299 sym.st_value = sp->n_value;
300 sym.st_size = 0;
301 sym.st_info = 0;
302 sym.st_other = 0;
303 switch (sp->n_type) {
304 case N_EXT + N_ABS:
305 sym.st_shndx = SHN_ABS;
306 break;
307 case N_COMM:
308 sym.st_shndx = SHN_COMMON;
309 break;
310 case N_EXT + N_UNDF:
311 sym.st_shndx = SHN_UNDEF;
312 break;
313 default:
314 sym.st_shndx = 0;
315 break;
316 }
317 return (&sym);
318 }
319
320 /*
321 * Process a.out format commons.
322 */
323 static struct nlist *
aout_find_com(struct nlist * sp,const char * name)324 aout_find_com(struct nlist *sp, const char *name)
325 {
326 static struct rtc_symb *rtcp = NULL;
327 struct rtc_symb *rs, *trs;
328 const char *sl;
329 char *cp;
330
331 /*
332 * See if common is already allocated.
333 */
334 trs = rtcp;
335 while (trs) {
336 sl = name;
337 cp = trs->rtc_sp->n_un.n_name;
338 while (*sl == *cp++)
339 if (*sl++ == '\0')
340 return (trs->rtc_sp);
341 trs = trs->rtc_next;
342 }
343
344 /*
345 * If we got here, common is not already allocated so allocate it.
346 */
347 if ((rs = malloc(sizeof (struct rtc_symb))) == NULL)
348 return (NULL);
349 if ((rs->rtc_sp = malloc(sizeof (struct nlist))) == NULL)
350 return (NULL);
351 trs = rtcp;
352 rtcp = rs;
353 rs->rtc_next = trs;
354 *(rs->rtc_sp) = *sp;
355 if ((rs->rtc_sp->n_un.n_name = malloc(strlen(name) + 1)) == NULL)
356 return (NULL);
357 (void) strcpy(rs->rtc_sp->n_un.n_name, name);
358 rs->rtc_sp->n_type = N_COMM;
359 if ((rs->rtc_sp->n_value =
360 (long)calloc(rs->rtc_sp->n_value, 1)) == NULL)
361 return (NULL);
362 return (rs->rtc_sp);
363 }
364
365 /*
366 * Find a.out format symbol in the specified link map. Unlike the sister
367 * elf routine we re-calculate the symbols hash value for each link map
368 * we're looking at.
369 */
370 static struct nlist *
aout_findsb(const char * aname,Rt_map * lmp,int flag)371 aout_findsb(const char *aname, Rt_map *lmp, int flag)
372 {
373 const char *name = aname;
374 char *cp;
375 struct fshash *p;
376 int i;
377 struct nlist *sp;
378 ulong_t hval = 0;
379
380 #define HASHMASK 0x7fffffff
381 #define RTHS 126
382
383 /*
384 * The name passed to us is in ELF format, thus it is necessary to
385 * map this back to the A_OUT format to compute the hash value (see
386 * mapping rules in aout_lookup_sym()). Basically the symbols are
387 * mapped according to whether a leading `.' exists.
388 *
389 * elf symbol a.out symbol
390 * i. .bar -> .bar (LKUP_LDOT)
391 * ii. .nuts -> nuts
392 * iii. foo -> _foo
393 */
394 if (*name == '.') {
395 if (!(flag & LKUP_LDOT))
396 name++;
397 } else
398 hval = '_';
399
400 while (*name)
401 hval = (hval << 1) + *name++;
402 hval = hval & HASHMASK;
403
404 i = hval % (AOUTDYN(lmp)->v2->ld_buckets == 0 ? RTHS :
405 AOUTDYN(lmp)->v2->ld_buckets);
406 p = LM2LP(lmp)->lp_hash + i;
407
408 if (p->fssymbno != -1) {
409 do {
410 sp = &LM2LP(lmp)->lp_symtab[p->fssymbno];
411 cp = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
412 name = aname;
413 if (*name == '.') {
414 if (!(flag & LKUP_LDOT))
415 name++;
416 } else {
417 cp++;
418 }
419 while (*name == *cp++) {
420 if (*name++ == '\0')
421 return (sp); /* found */
422 }
423 if (p->next == NULL)
424 return (NULL); /* not found */
425 else
426 continue;
427 } while ((p = &LM2LP(lmp)->lp_hash[p->next]) != NULL);
428 }
429 return (NULL);
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 int
aout_lookup_sym(Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)444 aout_lookup_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
445 {
446 char name[PATH_MAX];
447 Slookup sl = *slp;
448
449 DBG_CALL(Dbg_syms_lookup_aout(LIST(slp->sl_cmap), 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, srp, binfo, in_nfavl));
466 }
467
468 /*
469 * Symbol lookup for an a.out format module.
470 */
471 /* ARGSUSED3 */
472 static int
aout_find_sym(Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)473 aout_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
474 {
475 const char *name = slp->sl_name;
476 Rt_map *ilmp = slp->sl_imap;
477 struct nlist *sp;
478
479 DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_AOUT)));
480
481 if (sp = aout_findsb(name, ilmp, slp->sl_flags)) {
482 if (sp->n_value != 0) {
483 /*
484 * is it a common?
485 */
486 if (sp->n_type == (N_EXT + N_UNDF)) {
487 if ((sp = aout_find_com(sp, name)) == NULL)
488 return (0);
489 }
490 srp->sr_dmap = ilmp;
491 srp->sr_sym = aout_symconvert(sp);
492 *binfo |= DBG_BINFO_FOUND;
493 return (1);
494 }
495 }
496 return (0);
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 *
aout_new_lmp(Lm_list * lml,Aliste lmco,Fdesc * fdp,Addr addr,size_t msize,void * odyn,Rt_map * clmp,int * in_nfavl)505 aout_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize,
506 void *odyn, Rt_map *clmp, 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 == NULL) {
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) = NULL;
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 */
aout_get_so(const char * dir,const char * file,size_t dlen,size_t flen)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
aout_dladdr(ulong_t addr,Rt_map * lmp,Dl_info * dlip,void ** info,int flags)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 = NULL, _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 = NULL;
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 int
aout_dlsym_handle(Grp_hdl * ghp,Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)681 aout_dlsym_handle(Grp_hdl *ghp, Slookup *slp, Sresult *srp, uint_t *binfo,
682 int *in_nfavl)
683 {
684 char buffer[PATH_MAX];
685 Slookup sl;
686
687 if (dlsym_handle(ghp, slp, srp, binfo, in_nfavl))
688 return (1);
689
690 /*
691 * Symbol not found as supplied. However, most of our symbols will
692 * be in the "C" name space, where the implementation prepends a "_"
693 * to the symbol as it emits it. Therefore, attempt to find the
694 * symbol with the "_" prepend.
695 */
696 buffer[0] = '_';
697 (void) strcpy(&buffer[1], slp->sl_name);
698
699 sl = *slp;
700 sl.sl_name = (const char *)buffer;
701
702 return (dlsym_handle(ghp, &sl, srp, binfo, in_nfavl));
703 }
704
705 /*
706 * The initial mapping of the a.out occurs through exec(2), and presently this
707 * implementation doesn't provide a mmapobj_result_t array to ld.so.1. Thus,
708 * aout_get_mmap() is called to create the mapping information. Unlike ELF,
709 * the information that can be gathered from a mapped AOUT file, can be limited.
710 * In some cases the AOUT header isn't available in the mapped image, and thus
711 * this can't be inspected to determine the files size (the kernel always
712 * returns a pointer to the AOUT dynamic structure, but this is only sufficient
713 * to determine the size of the text segment).
714 *
715 * Therefore, the only generic mechanism of determining the AOUT's mapping is
716 * to use /proc. Only two mappings are required, the text (to determine any
717 * read-only region), and the data. The two mapping validate the range in
718 * which any relocations will occur. Should there be an additional bss segment,
719 * we don't care, as this can't be relocated, and we're never going to try
720 * unmapping the a.out.
721 */
722 #define PROCSIZE 20
723
724 int
aout_get_mmap(Lm_list * lml,mmapobj_result_t * mpp)725 aout_get_mmap(Lm_list *lml, mmapobj_result_t *mpp)
726 {
727 prmap_t *maps;
728 char proc[PROCSIZE];
729 int num, err, fd;
730
731 (void) snprintf(proc, PROCSIZE, MSG_ORIG(MSG_FMT_PROC),
732 EC_SWORD(getpid()));
733 if ((fd = open(proc, O_RDONLY)) == -1) {
734 err = errno;
735 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc,
736 strerror(err));
737 return (1);
738 }
739
740 if (ioctl(fd, PIOCNMAP, (void *)&num) == -1) {
741 err = errno;
742 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err));
743 return (1);
744 }
745
746 if ((maps = malloc((num + 1) * sizeof (prmap_t))) == NULL)
747 return (1);
748
749 if (ioctl(fd, PIOCMAP, (void *)maps) == -1) {
750 err = errno;
751 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), strerror(err));
752 free(maps);
753 return (1);
754 }
755
756 mpp->mr_addr = maps->pr_vaddr;
757 mpp->mr_fsize = mpp->mr_msize = maps->pr_size;
758 mpp->mr_prot = (PROT_READ | PROT_EXEC);
759
760 mpp++, maps++;
761
762 mpp->mr_addr = maps->pr_vaddr;
763 mpp->mr_fsize = mpp->mr_msize = maps->pr_size;
764 mpp->mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC);
765
766 maps--;
767 free(maps);
768 return (0);
769 }
770