xref: /onnv-gate/usr/src/cmd/sgs/libldstab/common/stab.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6812Sraf  * Common Development and Distribution License (the "License").
6*6812Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*6812Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6812Sraf  * Use is subject to license terms.
250Sstevel@tonic-gate  */
26*6812Sraf 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file contains all functions relating to stab processing.  The
310Sstevel@tonic-gate  * stab table is compressed by eliminating duplicate include file entries.
320Sstevel@tonic-gate  */
33*6812Sraf #include <stdio.h>
34*6812Sraf #include <string.h>
35*6812Sraf #include <stab.h>
36*6812Sraf #include <unistd.h>
37*6812Sraf #include <stdlib.h>
38*6812Sraf #include <signal.h>
39*6812Sraf #include <sys/param.h>
40*6812Sraf #include <errno.h>
41*6812Sraf #include <libintl.h>
42*6812Sraf #include "libld.h"
43*6812Sraf #include "msg.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * With the 5.x compiler, stab.h changed struct nlist into
480Sstevel@tonic-gate  * struct stab and got rid of it's embeded unions.
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate #if __SUNPRO_C >= 0x500 || defined(__GNUC__)
510Sstevel@tonic-gate #define	nlist	stab
520Sstevel@tonic-gate #else
530Sstevel@tonic-gate #define	n_strx	n_un.n_strx
540Sstevel@tonic-gate #endif
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Data structure that holds persistent data that sbfocus_symbol & sbfocus_close
590Sstevel@tonic-gate  * needs. Passing in a pointer to this struct makes them re-entrant.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate typedef struct sbld_tag {
620Sstevel@tonic-gate 	FILE	*fd;
630Sstevel@tonic-gate 	int	failed;
640Sstevel@tonic-gate } *Sbld, Sbld_rec;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 
670Sstevel@tonic-gate extern Sbld_rec		sb_data;
680Sstevel@tonic-gate extern const char	*out_fname, *in_fname;
690Sstevel@tonic-gate extern Half 		out_e_type;
700Sstevel@tonic-gate extern void		sbfocus_symbol(Sbld, const char *, const char *,
710Sstevel@tonic-gate 			    const char *);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #if	!defined(_ELF64)
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * holds information needed by sbfocus_symbol and sbfocus_close.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate Sbld_rec	sb_data = { NULL, 0 };
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * holds information out the output file being created.
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate const char	*out_fname = NULL;
840Sstevel@tonic-gate const char	*in_fname = NULL;	/* current input file */
850Sstevel@tonic-gate Half 		out_e_type = ET_NONE;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate  *  Signal handler is called when a SIGPIPE is encountered.  This would
890Sstevel@tonic-gate  *  happen in case `sbfocus' did not exist and `ld' is writing down a
900Sstevel@tonic-gate  *  pipe with no reader.  Trap signal and set failed field so that no
910Sstevel@tonic-gate  *  more subsequent writes occur.
920Sstevel@tonic-gate  */
930Sstevel@tonic-gate static void
940Sstevel@tonic-gate sigpipe_handler()
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	sb_data.failed = 1;
970Sstevel@tonic-gate }
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * sbfocus_symbol() will write one symbol to a pipe that has the program
1010Sstevel@tonic-gate  * "sbfocus" at the receiving end. If the program has not been started yet,
1020Sstevel@tonic-gate  * it is started, and the pipe established. "sbfocus" is started with the
1030Sstevel@tonic-gate  * function arguments "type" and "name" as its arguments, in that order.
1040Sstevel@tonic-gate  *
1050Sstevel@tonic-gate  * sbfocus_symbol() should be called with four arguments:
1060Sstevel@tonic-gate  *	data	Pointer to a Sbld struct that the caller has allocated in
1070Sstevel@tonic-gate  *		permanent storage. It must be the same struct for all related
1080Sstevel@tonic-gate  *		calls to sbfocus_symbol().
1090Sstevel@tonic-gate  *	name	This is the string name of the library/executable being built.
1100Sstevel@tonic-gate  *	type	A string, should be one of:
1110Sstevel@tonic-gate  *			"-x": Building an executable or shared object
1120Sstevel@tonic-gate  *			"-r": Concatenating object files
1130Sstevel@tonic-gate  *	symbol	The string that should be written to "sbfocus". If this
1140Sstevel@tonic-gate  *		argument is NULL "sbfocus" is started, but no symbol is
1150Sstevel@tonic-gate  *		written to it.
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate void
1180Sstevel@tonic-gate sbfocus_symbol(Sbld data, const char *name, const char *type,
1190Sstevel@tonic-gate     const char *symbol)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	int	fd[2], err;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (data->failed) {
1240Sstevel@tonic-gate 		return;
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	(void) signal(SIGPIPE, (void (*)(int)) sigpipe_handler);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (data->fd == NULL) {
1300Sstevel@tonic-gate 		data->failed = 0;
1310Sstevel@tonic-gate 		(void) pipe(fd);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 		switch (fork()) {
1340Sstevel@tonic-gate 		case -1:
1350Sstevel@tonic-gate 			err = errno;
1360Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK),
1370Sstevel@tonic-gate 			    in_fname, strerror(err),
1380Sstevel@tonic-gate 			    MSG_INTL(MSG_STAB_NOSBROW));
1390Sstevel@tonic-gate 			data->failed = 1;
1400Sstevel@tonic-gate 			(void) close(fd[0]);
1410Sstevel@tonic-gate 			(void) close(fd[1]);
1420Sstevel@tonic-gate 			return;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 		/*
1450Sstevel@tonic-gate 		 * Child process
1460Sstevel@tonic-gate 		 */
1470Sstevel@tonic-gate 		case 0:
1480Sstevel@tonic-gate 			(void) close(fd[1]);
1490Sstevel@tonic-gate 			(void) dup2(fd[0], fileno(stdin));
1500Sstevel@tonic-gate 			(void) close(fd[0]);
1510Sstevel@tonic-gate 			(void) execlp(MSG_ORIG(MSG_STR_SBFOCUS),
1520Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_SBFOCUS), type, name, 0);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 			err = errno;
1550Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC),
1560Sstevel@tonic-gate 			    in_fname, MSG_ORIG(MSG_STR_SBFOCUS),
1570Sstevel@tonic-gate 			    strerror(err), MSG_INTL(MSG_STAB_NOSBROW));
1580Sstevel@tonic-gate 			exit(-1);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 		/*
1610Sstevel@tonic-gate 		 * Parent process
1620Sstevel@tonic-gate 		 */
1630Sstevel@tonic-gate 		default:
1640Sstevel@tonic-gate 			(void) close(fd[0]);
1650Sstevel@tonic-gate 			data->fd = fdopen(fd[1], MSG_ORIG(MSG_STR_W));
1660Sstevel@tonic-gate 			break;
1670Sstevel@tonic-gate 		}
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 	if (symbol != NULL) {
1700Sstevel@tonic-gate 		(void) fputs(symbol, data->fd);
1710Sstevel@tonic-gate 		(void) putc('\n', data->fd);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate #endif /* !defined(_ELF64) */
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static Xword
1780Sstevel@tonic-gate pass1_stabindex(const Elf_Data *s_data, const Elf_Data *str_data,
1790Sstevel@tonic-gate 		const size_t cwd_len, const size_t name_len)
1800Sstevel@tonic-gate {
181*6812Sraf 	struct nlist	*elem;
182*6812Sraf 	struct nlist	*last = NULL;
183*6812Sraf 	size_t		i;
184*6812Sraf 	size_t		str_offset = 0;
185*6812Sraf 	size_t		new_size = 0;
186*6812Sraf 	size_t		first_object = 1;
187*6812Sraf 	size_t		any_obj = 0;
188*6812Sraf 	size_t		num_elem;
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * The processing of the stab table happens in two passes.
1910Sstevel@tonic-gate 	 *
1920Sstevel@tonic-gate 	 * first pass: calculate if any change is needed and if so, how much
1930Sstevel@tonic-gate 	 * the string table needs to be expanded by.
1940Sstevel@tonic-gate 	 */
1950Sstevel@tonic-gate 	num_elem = s_data->d_size / sizeof (struct nlist);
1960Sstevel@tonic-gate 	for (i = 0; i < num_elem; i++) {
1970Sstevel@tonic-gate 		char 	*str;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 		elem = (struct nlist *)s_data->d_buf + i;
2000Sstevel@tonic-gate 		switch (elem->n_type) {
2010Sstevel@tonic-gate 		case 0:
2020Sstevel@tonic-gate 			if (last)
2030Sstevel@tonic-gate 				str_offset += last->n_value;
2040Sstevel@tonic-gate 			last = elem;
2050Sstevel@tonic-gate 			break;
2060Sstevel@tonic-gate 		case N_OBJ:
2070Sstevel@tonic-gate 			str = (char *)str_data->d_buf + str_offset +
208*6812Sraf 			    elem->n_strx;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 			if ((*str == '\0') && first_object) {
2110Sstevel@tonic-gate 				/*
2120Sstevel@tonic-gate 				 * This is a 'CWD' N_OBJ
2130Sstevel@tonic-gate 				 *
2140Sstevel@tonic-gate 				 * we only record the 'cwd' once in each
2150Sstevel@tonic-gate 				 * stringtable.  so - we only need to add
2160Sstevel@tonic-gate 				 * it's length once to the new_size
2170Sstevel@tonic-gate 				 */
2180Sstevel@tonic-gate 				if (any_obj == 0) {
2190Sstevel@tonic-gate 					any_obj++;
2200Sstevel@tonic-gate 					new_size += cwd_len + 1;
2210Sstevel@tonic-gate 				} /* if */
2220Sstevel@tonic-gate 				first_object = 0;
2230Sstevel@tonic-gate 			} /* if */
2240Sstevel@tonic-gate 			else if (*str == '\0') {
2250Sstevel@tonic-gate 				/*
2260Sstevel@tonic-gate 				 * This is a 'object_name' N_OBJ
2270Sstevel@tonic-gate 				 */
2280Sstevel@tonic-gate 				new_size += name_len + 1;
2290Sstevel@tonic-gate 				first_object = 1;
2300Sstevel@tonic-gate 			} /* else if */
2310Sstevel@tonic-gate 			break;
2320Sstevel@tonic-gate 		default:
2330Sstevel@tonic-gate 			/* no-op */
2340Sstevel@tonic-gate 			break;
2350Sstevel@tonic-gate 		} /* switch */
2360Sstevel@tonic-gate 	} /* for */
2370Sstevel@tonic-gate 	/*LINTED*/
2380Sstevel@tonic-gate 	return ((Xword) new_size);
2390Sstevel@tonic-gate } /* pass1_stabindex */
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate static int
2430Sstevel@tonic-gate pass2_stabindex(Elf_Data *s_data, Elf_Data *str_data, const char *name,
2440Sstevel@tonic-gate 		size_t name_len, size_t cwd_pos, size_t free_pos)
2450Sstevel@tonic-gate {
246*6812Sraf 	struct nlist	*elem;
247*6812Sraf 	struct nlist	*last = NULL;
248*6812Sraf 	size_t		i;
249*6812Sraf 	size_t		str_offset = 0;
250*6812Sraf 	size_t		first_object = 1;
251*6812Sraf 	size_t		num_elem;
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * The processing of the stab table happens in two passes.
2540Sstevel@tonic-gate 	 *
2550Sstevel@tonic-gate 	 * first pass: calculate if any change is needed and if so, how much
2560Sstevel@tonic-gate 	 * the string table needs to be expanded by.
2570Sstevel@tonic-gate 	 */
2580Sstevel@tonic-gate 	num_elem = s_data->d_size / sizeof (struct nlist);
2590Sstevel@tonic-gate 	for (i = 0; i < num_elem; i++) {
2600Sstevel@tonic-gate 		char 	*str;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		elem = (struct nlist *)s_data->d_buf + i;
2630Sstevel@tonic-gate 		switch (elem->n_type) {
2640Sstevel@tonic-gate 		case 0:
2650Sstevel@tonic-gate 			if (last)
2660Sstevel@tonic-gate 				str_offset += last->n_value;
2670Sstevel@tonic-gate 			last = elem;
2680Sstevel@tonic-gate 			break;
2690Sstevel@tonic-gate 		case N_OBJ:
2700Sstevel@tonic-gate 			str = (char *)str_data->d_buf + str_offset +
271*6812Sraf 			    elem->n_strx;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 			if ((*str == '\0') && first_object) {
2740Sstevel@tonic-gate 				/*
2750Sstevel@tonic-gate 				 * This is a 'CWD' N_OBJ
2760Sstevel@tonic-gate 				 *
2770Sstevel@tonic-gate 				 * We point it at the CWD entry that we've
2780Sstevel@tonic-gate 				 * already placed in the new string_table.
2790Sstevel@tonic-gate 				 */
2800Sstevel@tonic-gate 				/*LINTED*/
2810Sstevel@tonic-gate 				elem->n_strx = (unsigned)(cwd_pos - str_offset);
2820Sstevel@tonic-gate 				first_object = 0;
2830Sstevel@tonic-gate 			} /* if */
2840Sstevel@tonic-gate 			else if (*str == '\0') {
2850Sstevel@tonic-gate 				/*
2860Sstevel@tonic-gate 				 * This is a 'object_name' N_OBJ.
2870Sstevel@tonic-gate 				 *
2880Sstevel@tonic-gate 				 * Append the object name to the string table
2890Sstevel@tonic-gate 				 * and set the elem->n_un.n_strx to point
2900Sstevel@tonic-gate 				 * to it.
2910Sstevel@tonic-gate 				 */
2920Sstevel@tonic-gate 				(void) strcpy((char *)str_data->d_buf +
293*6812Sraf 				    free_pos, name);
2940Sstevel@tonic-gate 				/*LINTED*/
2950Sstevel@tonic-gate 				elem->n_strx = (unsigned)(free_pos -
2960Sstevel@tonic-gate 				    str_offset);
2970Sstevel@tonic-gate 				free_pos += name_len + 1;
2980Sstevel@tonic-gate 				first_object = 1;
2990Sstevel@tonic-gate 			} /* if */
3000Sstevel@tonic-gate 			break;
3010Sstevel@tonic-gate 		default:
3020Sstevel@tonic-gate 			break;
3030Sstevel@tonic-gate 		} /* switch */
3040Sstevel@tonic-gate 	} /* for */
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/*LINTED*/
3070Sstevel@tonic-gate 	last->n_value = (unsigned)(str_data->d_size - str_offset);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	return (1);
3100Sstevel@tonic-gate } /* pass2_stabindex() */
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate  * find_scn()
3150Sstevel@tonic-gate  *
3160Sstevel@tonic-gate  *	Find a section in elf that matches the supplied section name,
3170Sstevel@tonic-gate  *	type, and flags.
3180Sstevel@tonic-gate  *
3190Sstevel@tonic-gate  * Returns:
3200Sstevel@tonic-gate  *		section number if found
3210Sstevel@tonic-gate  *		 0 - if no matching section found
3220Sstevel@tonic-gate  *		-1 - if error
3230Sstevel@tonic-gate  *
3240Sstevel@tonic-gate  *	If shdr is a non-null pointer it will be set to the section header
3250Sstevel@tonic-gate  *	that was found.
3260Sstevel@tonic-gate  */
3270Sstevel@tonic-gate static size_t
3280Sstevel@tonic-gate find_scn(Elf *elf, const char *elf_strtab, const char *name,
3290Sstevel@tonic-gate 	const Word sh_type, const Xword sh_flags, Elf_Scn **ret_scn)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate 	Elf_Scn		*scn = NULL;
3320Sstevel@tonic-gate 	Shdr		*scn_shdr;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	while ((scn = elf_nextscn(elf, scn)) != 0) {
3350Sstevel@tonic-gate 		if ((scn_shdr = elf_getshdr(scn)) == NULL)
3360Sstevel@tonic-gate 			return ((size_t)-1);
3370Sstevel@tonic-gate 		if ((scn_shdr->sh_type == sh_type) &&
3380Sstevel@tonic-gate 		    (scn_shdr->sh_flags == sh_flags) &&
3390Sstevel@tonic-gate 		    (strcmp(elf_strtab + scn_shdr->sh_name, name) == 0)) {
3400Sstevel@tonic-gate 			size_t scn_ndx;
3410Sstevel@tonic-gate 			/*
3420Sstevel@tonic-gate 			 * we've got a match
3430Sstevel@tonic-gate 			 */
3440Sstevel@tonic-gate 			if ((scn_ndx = elf_ndxscn(scn)) == SHN_UNDEF)
3450Sstevel@tonic-gate 				return ((size_t)-1);
3460Sstevel@tonic-gate 			if (ret_scn)
3470Sstevel@tonic-gate 				*ret_scn = scn;
3480Sstevel@tonic-gate 			return (scn_ndx);
3490Sstevel@tonic-gate 		} /* if */
3500Sstevel@tonic-gate 	} /* while */
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * no match found
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	return (0);
3560Sstevel@tonic-gate } /* find_scn() */
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate static Elf_Data *
3600Sstevel@tonic-gate get_str_data(Elf *elf, const char *strtab, const char *name, Shdr *shdr)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	Elf_Scn		*str_scn;
3630Sstevel@tonic-gate 	Elf_Data	*str_data;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * The stab's string table can be found through the
3670Sstevel@tonic-gate 	 * shdr->sh_link value.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	if (shdr->sh_link == 0) {
3700Sstevel@tonic-gate 		/*
3710Sstevel@tonic-gate 		 * Normally the sh_link field should point to the
3720Sstevel@tonic-gate 		 * required strtab.  But if it's not filled in (which
3730Sstevel@tonic-gate 		 * means something goofed somewhere) we will try to look
3740Sstevel@tonic-gate 		 * it up from the elf file itself.
3750Sstevel@tonic-gate 		 */
3760Sstevel@tonic-gate 		size_t	strscn_ndx;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		strscn_ndx = find_scn(elf, strtab, name, SHT_STRTAB,
3790Sstevel@tonic-gate 		    shdr->sh_flags, &str_scn);
3800Sstevel@tonic-gate 		if (strscn_ndx == 0) {
3810Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_STAB_MISTBL),
382*6812Sraf 			    in_fname);
3830Sstevel@tonic-gate 			return ((Elf_Data *)S_ERROR);
3840Sstevel@tonic-gate 		} else if (strscn_ndx == (size_t)-1) {
3850Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_STAB_BADTBL),
386*6812Sraf 			    in_fname);
3870Sstevel@tonic-gate 			return ((Elf_Data *)S_ERROR);
3880Sstevel@tonic-gate 		}
3890Sstevel@tonic-gate 	} else {
3900Sstevel@tonic-gate 		if ((str_scn = elf_getscn(elf, shdr->sh_link)) == NULL) {
3910Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSCN),
392*6812Sraf 			    in_fname, elf_errmsg(0));
3930Sstevel@tonic-gate 			return ((Elf_Data *)S_ERROR);
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if ((str_data = elf_getdata(str_scn, NULL)) == NULL) {
3980Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA), in_fname,
399*6812Sraf 		    elf_errmsg(0));
4000Sstevel@tonic-gate 		return ((Elf_Data *)S_ERROR);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	return (str_data);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate /*
4100Sstevel@tonic-gate  * We examine all the stab's looking for pairs of N_OBJ's who's
4110Sstevel@tonic-gate  * string pointers (elem->n_un.n_strx) points to a null string.
4120Sstevel@tonic-gate  * When we find a pair we set the first string pointing to the
4130Sstevel@tonic-gate  * CWD and we set the second string to the file object name (*name).
4140Sstevel@tonic-gate  *
4150Sstevel@tonic-gate  * The stab's string table will have to be expanded to hold
4160Sstevel@tonic-gate  * these new enties.
4170Sstevel@tonic-gate  */
4180Sstevel@tonic-gate static void
4190Sstevel@tonic-gate process_stabindex(Elf *elf, const char *elf_strtab, const char *strtab_name,
4200Sstevel@tonic-gate     Shdr *shdr, Elf_Data *s_data)
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate 	Elf_Data	*str_data;
4230Sstevel@tonic-gate 	static char	*cwd = NULL;
4240Sstevel@tonic-gate 	static size_t 	cwd_len;
425*6812Sraf 	size_t 		new_size;
426*6812Sraf 	size_t 		cwd_pos;
427*6812Sraf 	size_t 		name_len;
4280Sstevel@tonic-gate 	Elf_Void	*data;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if ((str_data = get_str_data(elf, elf_strtab, strtab_name,
4310Sstevel@tonic-gate 	    shdr)) == (Elf_Data *)S_ERROR)
4320Sstevel@tonic-gate 		return;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (cwd == NULL) {
4350Sstevel@tonic-gate 		if ((cwd = getcwd(NULL, MAXPATHLEN)) == NULL) {
4360Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_GETCWD),
437*6812Sraf 			    in_fname, strerror(errno));
4380Sstevel@tonic-gate 			return;
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 		cwd_len = strlen(cwd);
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 	name_len = strlen(in_fname);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	new_size = pass1_stabindex(s_data, str_data, cwd_len, name_len);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if (new_size == 0)
4470Sstevel@tonic-gate 		/* no changes are needed */
4480Sstevel@tonic-gate 		return;
4490Sstevel@tonic-gate 	/*
4500Sstevel@tonic-gate 	 * The .stab.index data buffer must be updated so a new copy is
4510Sstevel@tonic-gate 	 * allocated.  The original is read-only.
4520Sstevel@tonic-gate 	 */
4530Sstevel@tonic-gate 	if ((data = malloc(s_data->d_size)) == 0)
4540Sstevel@tonic-gate 		return;
4550Sstevel@tonic-gate 	(void) memcpy(data, s_data->d_buf, s_data->d_size);
4560Sstevel@tonic-gate 	s_data->d_buf = data;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * Allocate a new .stab.indexstr that is big enough to hold the new
4600Sstevel@tonic-gate 	 * entries that we will need to place into it.
4610Sstevel@tonic-gate 	 *
4620Sstevel@tonic-gate 	 * Then append the 'cwd' onto the end of the current data.
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	if ((data = malloc(str_data->d_size + new_size)) == 0)
4650Sstevel@tonic-gate 		return;
4660Sstevel@tonic-gate 	(void) memcpy(data, str_data->d_buf, str_data->d_size);
4670Sstevel@tonic-gate 	cwd_pos = str_data->d_size;
4680Sstevel@tonic-gate 	(void) strcpy((char *)data + cwd_pos, cwd);
4690Sstevel@tonic-gate 	str_data->d_buf = data;
4700Sstevel@tonic-gate 	str_data->d_size = str_data->d_size + new_size;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	(void) pass2_stabindex(s_data, str_data, in_fname, name_len, cwd_pos,
473*6812Sraf 	    cwd_pos + cwd_len + 1);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate static void
4780Sstevel@tonic-gate process_stabsbfocus(Elf *elf, const char *elf_strtab,
4790Sstevel@tonic-gate     const char *strtab_name, Shdr *shdr, Elf_Data *s_data,
4800Sstevel@tonic-gate     const char *out_name, Half etype)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	Elf_Data	*str_data;
4830Sstevel@tonic-gate 	struct nlist	*elem, *last = NULL;
4840Sstevel@tonic-gate 	size_t		i, str_offset = 0, num_elem;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if ((str_data = get_str_data(elf, elf_strtab, strtab_name,
4870Sstevel@tonic-gate 	    shdr)) == (Elf_Data *)S_ERROR)
4880Sstevel@tonic-gate 		return;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	num_elem = s_data->d_size / sizeof (struct nlist);
4910Sstevel@tonic-gate 	for (i = 0; i < num_elem; i++) {
4920Sstevel@tonic-gate 		const char	*type, *str;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		elem = (struct nlist *)s_data->d_buf + i;
4950Sstevel@tonic-gate 		switch (elem->n_type) {
4960Sstevel@tonic-gate 		case 0:
4970Sstevel@tonic-gate 			if (last)
4980Sstevel@tonic-gate 				str_offset += last->n_value;
4990Sstevel@tonic-gate 			last = elem;
5000Sstevel@tonic-gate 			break;
5010Sstevel@tonic-gate 		case N_BROWS:
5020Sstevel@tonic-gate 			str = (char *)str_data->d_buf + elem->n_strx +
5030Sstevel@tonic-gate 			    str_offset;
5040Sstevel@tonic-gate 			if (etype == ET_REL)
5050Sstevel@tonic-gate 				type = MSG_ORIG(MSG_STR_DASHR);
5060Sstevel@tonic-gate 			else
5070Sstevel@tonic-gate 				type = MSG_ORIG(MSG_STR_DASHX);
5080Sstevel@tonic-gate 			sbfocus_symbol(&sb_data, out_name, type, str);
5090Sstevel@tonic-gate 			break;
5100Sstevel@tonic-gate 		default:
5110Sstevel@tonic-gate 			/* no-op */
5120Sstevel@tonic-gate 			break;
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate /* ARGSUSED2 */
5190Sstevel@tonic-gate void
5200Sstevel@tonic-gate #if	defined(_ELF64)
5210Sstevel@tonic-gate ld_start64(const char *out_name, const Half etype, const char *caller)
5220Sstevel@tonic-gate #else
5230Sstevel@tonic-gate ld_start(const char *out_name, const Half etype, const char *caller)
5240Sstevel@tonic-gate #endif
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	out_fname = out_name;
5270Sstevel@tonic-gate 	out_e_type = etype;
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate /* ARGSUSED1 */
5320Sstevel@tonic-gate void
5330Sstevel@tonic-gate #if	defined(_ELF64)
5340Sstevel@tonic-gate ld_file64(const char *name, const Elf_Kind kind, int flags, Elf *elf)
5350Sstevel@tonic-gate #else
5360Sstevel@tonic-gate ld_file(const char *name, const Elf_Kind kind, int flags, Elf *elf)
5370Sstevel@tonic-gate #endif
5380Sstevel@tonic-gate {
5390Sstevel@tonic-gate 	in_fname = name;
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * ld_section()
5450Sstevel@tonic-gate  *
5460Sstevel@tonic-gate  * Args:
5470Sstevel@tonic-gate  *	name	- pointer to name of current section being processed.
5480Sstevel@tonic-gate  *	shdr	- pointer to Section Header of current in-file being
5490Sstevel@tonic-gate  *		  processed.
5500Sstevel@tonic-gate  *	s_data	- pointer to Section Data structure of current in-file
5510Sstevel@tonic-gate  *		  being processed.
5520Sstevel@tonic-gate  *	elf	- pointer to elf structure for current in-file being
5530Sstevel@tonic-gate  *		  processed
5540Sstevel@tonic-gate  */
5550Sstevel@tonic-gate /* ARGSUSED2 */
5560Sstevel@tonic-gate void
5570Sstevel@tonic-gate #if	defined(_ELF64)
5580Sstevel@tonic-gate ld_section64(const char *scn_name, Shdr *shdr, Word scnndx,
5590Sstevel@tonic-gate #else
5600Sstevel@tonic-gate ld_section(const char *scn_name, Shdr *shdr, Word scnndx,
5610Sstevel@tonic-gate #endif
5620Sstevel@tonic-gate 	Elf_Data *s_data, Elf *elf)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	Ehdr		*ehdr;
5650Sstevel@tonic-gate 	Elf_Data	*str_data;
5660Sstevel@tonic-gate 	Elf_Scn		*str_scn;
5670Sstevel@tonic-gate 	char		*strtab;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	ehdr = elf_getehdr(elf);
5700Sstevel@tonic-gate 	if ((ehdr->e_type != ET_DYN) && (shdr->sh_type == SHT_PROGBITS)) {
5710Sstevel@tonic-gate 		/*
5720Sstevel@tonic-gate 		 * this is a minor optimization for speed.  If it's not a
5730Sstevel@tonic-gate 		 * stab string we aren't going to strcmp() it.
5740Sstevel@tonic-gate 		 */
5750Sstevel@tonic-gate 		if ((scn_name[1] == 's') &&
5760Sstevel@tonic-gate 		    (scn_name[2] == 't') &&
5770Sstevel@tonic-gate 		    (scn_name[3] == 'a') &&
5780Sstevel@tonic-gate 		    (scn_name[4] == 'b')) {
5790Sstevel@tonic-gate 			Word	shstrndx;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 			/*
5820Sstevel@tonic-gate 			 * If 'extended sections' are in use, then
5830Sstevel@tonic-gate 			 *	e_shstrndx == Shdr[0].sh_link
5840Sstevel@tonic-gate 			 */
5850Sstevel@tonic-gate 			if (ehdr->e_shstrndx == SHN_XINDEX) {
5860Sstevel@tonic-gate 				Elf_Scn	*scn0;
5870Sstevel@tonic-gate 				Shdr	*shdr0;
5880Sstevel@tonic-gate 				scn0 = elf_getscn(elf, 0);
5890Sstevel@tonic-gate 				shdr0 = elf_getshdr(scn0);
5900Sstevel@tonic-gate 				shstrndx = shdr0->sh_link;
5910Sstevel@tonic-gate 			} else
5920Sstevel@tonic-gate 				shstrndx = ehdr->e_shstrndx;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 			str_scn = elf_getscn(elf, shstrndx);
5950Sstevel@tonic-gate 			str_data = elf_getdata(str_scn, NULL);
5960Sstevel@tonic-gate 			strtab = str_data->d_buf;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 			if (strcmp(scn_name, MSG_ORIG(MSG_SCN_STAB)) == 0) {
5990Sstevel@tonic-gate 				/*
6000Sstevel@tonic-gate 				 * Process .stab
6010Sstevel@tonic-gate 				 */
6020Sstevel@tonic-gate 				process_stabsbfocus(elf, strtab,
6030Sstevel@tonic-gate 				    MSG_ORIG(MSG_SCN_STABSTR), shdr,
6040Sstevel@tonic-gate 				    s_data, out_fname, out_e_type);
6050Sstevel@tonic-gate 			} else if (strcmp(scn_name,
6060Sstevel@tonic-gate 			    MSG_ORIG(MSG_SCN_STABINDEX)) == 0) {
6070Sstevel@tonic-gate 				/*
6080Sstevel@tonic-gate 				 * Process .stab.index
6090Sstevel@tonic-gate 				 */
6100Sstevel@tonic-gate 				process_stabindex(elf, strtab,
6110Sstevel@tonic-gate 				    MSG_ORIG(MSG_SCN_STABINDEXSTR), shdr,
6120Sstevel@tonic-gate 				    s_data);
6130Sstevel@tonic-gate 			} else if (strcmp(scn_name,
6140Sstevel@tonic-gate 			    MSG_ORIG(MSG_SCN_STABSBFOCUS)) == 0) {
6150Sstevel@tonic-gate 				/*
6160Sstevel@tonic-gate 				 * Process .stab.sbfocus
6170Sstevel@tonic-gate 				 */
6180Sstevel@tonic-gate 				process_stabsbfocus(elf, strtab,
6190Sstevel@tonic-gate 				    MSG_ORIG(MSG_SCN_STABSBFOCUSTR), shdr,
6200Sstevel@tonic-gate 				    s_data, out_fname, out_e_type);
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate  * Null atexit() routine, causes dlsym() to pass and thus no dlerror() message
6280Sstevel@tonic-gate  * generation.
6290Sstevel@tonic-gate  */
6300Sstevel@tonic-gate /* ARGSUSED */
6310Sstevel@tonic-gate void
6320Sstevel@tonic-gate #if	defined(_ELF64)
6330Sstevel@tonic-gate ld_atexit64(int status)
6340Sstevel@tonic-gate #else
6350Sstevel@tonic-gate ld_atexit(int status)
6360Sstevel@tonic-gate #endif
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate #if	!defined(_ELF64)
6410Sstevel@tonic-gate /*
642*6812Sraf  * Messaging support - funnel everything through dgettext().
6430Sstevel@tonic-gate  */
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate const char *
6460Sstevel@tonic-gate _libldstab_msg(Msg mid)
6470Sstevel@tonic-gate {
648*6812Sraf 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate #endif
651