xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/a.out.c (revision c6867562)
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_USRLIB),		MSG_PTH_USRLIB_SIZE },
54 	{ MSG_ORIG(MSG_PTH_USRLCLIB),		MSG_PTH_USRLCLIB_SIZE },
55 	{ 0, 0 }
56 };
57 
58 static Spath_defn _aout_sec_dirs[] = {
59 	{ MSG_ORIG(MSG_PTH_LIBSE),		MSG_PTH_LIBSE_SIZE },
60 	{ 0, 0 }
61 };
62 
63 Alist	*aout_def_dirs = NULL;
64 Alist	*aout_sec_dirs = NULL;
65 
66 /*
67  * Defines for local functions.
68  */
69 static void	aout_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int);
70 static int	aout_dlsym_handle(Grp_hdl *, Slookup *, Sresult *, uint_t *,
71 		    int *);
72 static Addr	aout_entry_point(void);
73 static int	aout_find_sym(Slookup *, Sresult *, uint_t *, int *);
74 static int	aout_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t);
75 static Alist	**aout_get_def_dirs(void);
76 static Alist	**aout_get_sec_dirs(void);
77 static char	*aout_get_so(const char *, const char *, size_t, size_t);
78 static int	aout_needed(Lm_list *, Aliste, Rt_map *, int *);
79 
80 /*
81  * Functions and data accessed through indirect pointers.
82  */
83 Fct 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  */
101 static Alist **
aout_get_def_dirs()102 aout_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 
109 static Alist **
aout_get_sec_dirs()110 aout_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 */
124 static int
aout_fix_name(const char * oname,Rt_map * clmp,Alist ** alpp,Aliste alni,uint_t orig)125 aout_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  */
163 Fct *
164 /* ARGSUSED1 */
aout_verify(caddr_t addr,size_t size,Fdesc * fdp,const char * name,Rej_desc * rej)165 aout_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  */
183 static Addr
aout_entry_point()184 aout_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  */
195 static int
aout_needed(Lm_list * lml,Aliste lmco,Rt_map * clmp,int * in_nfavl)196 aout_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 
293 static Sym *
aout_symconvert(struct nlist * sp)294 aout_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  */
322 static struct nlist *
aout_find_com(struct nlist * sp,const char * name)323 aout_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  */
369 static struct nlist *
aout_findsb(const char * aname,Rt_map * lmp,int flag)370 aout_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  */
442 int
aout_lookup_sym(Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)443 aout_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 */
471 static int
aout_find_sym(Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)472 aout_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 */
503 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)504 aout_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  */
599 static char *
600 /* ARGSUSED2 */
aout_get_so(const char * dir,const char * file,size_t dlen,size_t flen)601 aout_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  */
617 static void
aout_dladdr(ulong_t addr,Rt_map * lmp,Dl_info * dlip,void ** info,int flags)618 aout_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  */
679 static int
aout_dlsym_handle(Grp_hdl * ghp,Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)680 aout_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 
723 int
aout_get_mmap(Lm_list * lml,mmapobj_result_t * mpp)724 aout_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