xref: /illumos-gate/usr/src/cmd/sgs/libldstab/common/stab.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contains all functions relating to stab processing.  The
31  * stab table is compressed by eliminating duplicate include file entries.
32  */
33 #include <stdio.h>
34 #include <string.h>
35 #include <stab.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include <sys/param.h>
40 #include <errno.h>
41 #include <libintl.h>
42 #include "libld.h"
43 #include "msg.h"
44 
45 
46 /*
47  * With the 5.x compiler, stab.h changed struct nlist into
48  * struct stab and got rid of it's embeded unions.
49  */
50 #if __SUNPRO_C >= 0x500 || defined(__GNUC__)
51 #define	nlist	stab
52 #else
53 #define	n_strx	n_un.n_strx
54 #endif
55 
56 
57 /*
58  * Data structure that holds persistent data that sbfocus_symbol & sbfocus_close
59  * needs. Passing in a pointer to this struct makes them re-entrant.
60  */
61 typedef struct sbld_tag {
62 	FILE	*fd;
63 	int	failed;
64 } *Sbld, Sbld_rec;
65 
66 
67 extern Sbld_rec		sb_data;
68 extern const char	*out_fname, *in_fname;
69 extern Half 		out_e_type;
70 extern void		sbfocus_symbol(Sbld, const char *, const char *,
71 			    const char *);
72 
73 #if	!defined(_ELF64)
74 
75 /*
76  * holds information needed by sbfocus_symbol and sbfocus_close.
77  */
78 Sbld_rec	sb_data = { NULL, 0 };
79 
80 /*
81  * holds information out the output file being created.
82  */
83 const char	*out_fname = NULL;
84 const char	*in_fname = NULL;	/* current input file */
85 Half 		out_e_type = ET_NONE;
86 
87 /*
88  *  Signal handler is called when a SIGPIPE is encountered.  This would
89  *  happen in case `sbfocus' did not exist and `ld' is writing down a
90  *  pipe with no reader.  Trap signal and set failed field so that no
91  *  more subsequent writes occur.
92  */
93 static void
94 sigpipe_handler()
95 {
96 	sb_data.failed = 1;
97 }
98 
99 /*
100  * sbfocus_symbol() will write one symbol to a pipe that has the program
101  * "sbfocus" at the receiving end. If the program has not been started yet,
102  * it is started, and the pipe established. "sbfocus" is started with the
103  * function arguments "type" and "name" as its arguments, in that order.
104  *
105  * sbfocus_symbol() should be called with four arguments:
106  *	data	Pointer to a Sbld struct that the caller has allocated in
107  *		permanent storage. It must be the same struct for all related
108  *		calls to sbfocus_symbol().
109  *	name	This is the string name of the library/executable being built.
110  *	type	A string, should be one of:
111  *			"-x": Building an executable or shared object
112  *			"-r": Concatenating object files
113  *	symbol	The string that should be written to "sbfocus". If this
114  *		argument is NULL "sbfocus" is started, but no symbol is
115  *		written to it.
116  */
117 void
118 sbfocus_symbol(Sbld data, const char *name, const char *type,
119     const char *symbol)
120 {
121 	int	fd[2], err;
122 
123 	if (data->failed) {
124 		return;
125 	}
126 
127 	(void) signal(SIGPIPE, (void (*)(int)) sigpipe_handler);
128 
129 	if (data->fd == NULL) {
130 		data->failed = 0;
131 		(void) pipe(fd);
132 
133 		switch (fork()) {
134 		case -1:
135 			err = errno;
136 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK),
137 			    in_fname, strerror(err),
138 			    MSG_INTL(MSG_STAB_NOSBROW));
139 			data->failed = 1;
140 			(void) close(fd[0]);
141 			(void) close(fd[1]);
142 			return;
143 
144 		/*
145 		 * Child process
146 		 */
147 		case 0:
148 			(void) close(fd[1]);
149 			(void) dup2(fd[0], fileno(stdin));
150 			(void) close(fd[0]);
151 			(void) execlp(MSG_ORIG(MSG_STR_SBFOCUS),
152 			    MSG_ORIG(MSG_STR_SBFOCUS), type, name, 0);
153 
154 			err = errno;
155 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC),
156 			    in_fname, MSG_ORIG(MSG_STR_SBFOCUS),
157 			    strerror(err), MSG_INTL(MSG_STAB_NOSBROW));
158 			exit(-1);
159 
160 		/*
161 		 * Parent process
162 		 */
163 		default:
164 			(void) close(fd[0]);
165 			data->fd = fdopen(fd[1], MSG_ORIG(MSG_STR_W));
166 			break;
167 		}
168 	}
169 	if (symbol != NULL) {
170 		(void) fputs(symbol, data->fd);
171 		(void) putc('\n', data->fd);
172 	}
173 }
174 #endif /* !defined(_ELF64) */
175 
176 
177 static Xword
178 pass1_stabindex(const Elf_Data *s_data, const Elf_Data *str_data,
179 		const size_t cwd_len, const size_t name_len)
180 {
181 	struct nlist	*elem;
182 	struct nlist	*last = NULL;
183 	size_t		i;
184 	size_t		str_offset = 0;
185 	size_t		new_size = 0;
186 	size_t		first_object = 1;
187 	size_t		any_obj = 0;
188 	size_t		num_elem;
189 	/*
190 	 * The processing of the stab table happens in two passes.
191 	 *
192 	 * first pass: calculate if any change is needed and if so, how much
193 	 * the string table needs to be expanded by.
194 	 */
195 	num_elem = s_data->d_size / sizeof (struct nlist);
196 	for (i = 0; i < num_elem; i++) {
197 		char 	*str;
198 
199 		elem = (struct nlist *)s_data->d_buf + i;
200 		switch (elem->n_type) {
201 		case 0:
202 			if (last)
203 				str_offset += last->n_value;
204 			last = elem;
205 			break;
206 		case N_OBJ:
207 			str = (char *)str_data->d_buf + str_offset +
208 			    elem->n_strx;
209 
210 			if ((*str == '\0') && first_object) {
211 				/*
212 				 * This is a 'CWD' N_OBJ
213 				 *
214 				 * we only record the 'cwd' once in each
215 				 * stringtable.  so - we only need to add
216 				 * it's length once to the new_size
217 				 */
218 				if (any_obj == 0) {
219 					any_obj++;
220 					new_size += cwd_len + 1;
221 				} /* if */
222 				first_object = 0;
223 			} /* if */
224 			else if (*str == '\0') {
225 				/*
226 				 * This is a 'object_name' N_OBJ
227 				 */
228 				new_size += name_len + 1;
229 				first_object = 1;
230 			} /* else if */
231 			break;
232 		default:
233 			/* no-op */
234 			break;
235 		} /* switch */
236 	} /* for */
237 	/*LINTED*/
238 	return ((Xword) new_size);
239 } /* pass1_stabindex */
240 
241 
242 static int
243 pass2_stabindex(Elf_Data *s_data, Elf_Data *str_data, const char *name,
244 		size_t name_len, size_t cwd_pos, size_t free_pos)
245 {
246 	struct nlist	*elem;
247 	struct nlist	*last = NULL;
248 	size_t		i;
249 	size_t		str_offset = 0;
250 	size_t		first_object = 1;
251 	size_t		num_elem;
252 	/*
253 	 * The processing of the stab table happens in two passes.
254 	 *
255 	 * first pass: calculate if any change is needed and if so, how much
256 	 * the string table needs to be expanded by.
257 	 */
258 	num_elem = s_data->d_size / sizeof (struct nlist);
259 	for (i = 0; i < num_elem; i++) {
260 		char 	*str;
261 
262 		elem = (struct nlist *)s_data->d_buf + i;
263 		switch (elem->n_type) {
264 		case 0:
265 			if (last)
266 				str_offset += last->n_value;
267 			last = elem;
268 			break;
269 		case N_OBJ:
270 			str = (char *)str_data->d_buf + str_offset +
271 			    elem->n_strx;
272 
273 			if ((*str == '\0') && first_object) {
274 				/*
275 				 * This is a 'CWD' N_OBJ
276 				 *
277 				 * We point it at the CWD entry that we've
278 				 * already placed in the new string_table.
279 				 */
280 				/*LINTED*/
281 				elem->n_strx = (unsigned)(cwd_pos - str_offset);
282 				first_object = 0;
283 			} /* if */
284 			else if (*str == '\0') {
285 				/*
286 				 * This is a 'object_name' N_OBJ.
287 				 *
288 				 * Append the object name to the string table
289 				 * and set the elem->n_un.n_strx to point
290 				 * to it.
291 				 */
292 				(void) strcpy((char *)str_data->d_buf +
293 				    free_pos, name);
294 				/*LINTED*/
295 				elem->n_strx = (unsigned)(free_pos -
296 				    str_offset);
297 				free_pos += name_len + 1;
298 				first_object = 1;
299 			} /* if */
300 			break;
301 		default:
302 			break;
303 		} /* switch */
304 	} /* for */
305 
306 	/*LINTED*/
307 	last->n_value = (unsigned)(str_data->d_size - str_offset);
308 
309 	return (1);
310 } /* pass2_stabindex() */
311 
312 
313 /*
314  * find_scn()
315  *
316  *	Find a section in elf that matches the supplied section name,
317  *	type, and flags.
318  *
319  * Returns:
320  *		section number if found
321  *		 0 - if no matching section found
322  *		-1 - if error
323  *
324  *	If shdr is a non-null pointer it will be set to the section header
325  *	that was found.
326  */
327 static size_t
328 find_scn(Elf *elf, const char *elf_strtab, const char *name,
329 	const Word sh_type, const Xword sh_flags, Elf_Scn **ret_scn)
330 {
331 	Elf_Scn		*scn = NULL;
332 	Shdr		*scn_shdr;
333 
334 	while ((scn = elf_nextscn(elf, scn)) != 0) {
335 		if ((scn_shdr = elf_getshdr(scn)) == NULL)
336 			return ((size_t)-1);
337 		if ((scn_shdr->sh_type == sh_type) &&
338 		    (scn_shdr->sh_flags == sh_flags) &&
339 		    (strcmp(elf_strtab + scn_shdr->sh_name, name) == 0)) {
340 			size_t scn_ndx;
341 			/*
342 			 * we've got a match
343 			 */
344 			if ((scn_ndx = elf_ndxscn(scn)) == SHN_UNDEF)
345 				return ((size_t)-1);
346 			if (ret_scn)
347 				*ret_scn = scn;
348 			return (scn_ndx);
349 		} /* if */
350 	} /* while */
351 
352 	/*
353 	 * no match found
354 	 */
355 	return (0);
356 } /* find_scn() */
357 
358 
359 static Elf_Data *
360 get_str_data(Elf *elf, const char *strtab, const char *name, Shdr *shdr)
361 {
362 	Elf_Scn		*str_scn;
363 	Elf_Data	*str_data;
364 
365 	/*
366 	 * The stab's string table can be found through the
367 	 * shdr->sh_link value.
368 	 */
369 	if (shdr->sh_link == 0) {
370 		/*
371 		 * Normally the sh_link field should point to the
372 		 * required strtab.  But if it's not filled in (which
373 		 * means something goofed somewhere) we will try to look
374 		 * it up from the elf file itself.
375 		 */
376 		size_t	strscn_ndx;
377 
378 		strscn_ndx = find_scn(elf, strtab, name, SHT_STRTAB,
379 		    shdr->sh_flags, &str_scn);
380 		if (strscn_ndx == 0) {
381 			(void) fprintf(stderr, MSG_INTL(MSG_STAB_MISTBL),
382 			    in_fname);
383 			return ((Elf_Data *)S_ERROR);
384 		} else if (strscn_ndx == (size_t)-1) {
385 			(void) fprintf(stderr, MSG_INTL(MSG_STAB_BADTBL),
386 			    in_fname);
387 			return ((Elf_Data *)S_ERROR);
388 		}
389 	} else {
390 		if ((str_scn = elf_getscn(elf, shdr->sh_link)) == NULL) {
391 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSCN),
392 			    in_fname, elf_errmsg(0));
393 			return ((Elf_Data *)S_ERROR);
394 		}
395 	}
396 
397 	if ((str_data = elf_getdata(str_scn, NULL)) == NULL) {
398 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA), in_fname,
399 		    elf_errmsg(0));
400 		return ((Elf_Data *)S_ERROR);
401 	}
402 
403 	return (str_data);
404 }
405 
406 
407 
408 
409 /*
410  * We examine all the stab's looking for pairs of N_OBJ's who's
411  * string pointers (elem->n_un.n_strx) points to a null string.
412  * When we find a pair we set the first string pointing to the
413  * CWD and we set the second string to the file object name (*name).
414  *
415  * The stab's string table will have to be expanded to hold
416  * these new enties.
417  */
418 static void
419 process_stabindex(Elf *elf, const char *elf_strtab, const char *strtab_name,
420     Shdr *shdr, Elf_Data *s_data)
421 {
422 	Elf_Data	*str_data;
423 	static char	*cwd = NULL;
424 	static size_t 	cwd_len;
425 	size_t 		new_size;
426 	size_t 		cwd_pos;
427 	size_t 		name_len;
428 	Elf_Void	*data;
429 
430 	if ((str_data = get_str_data(elf, elf_strtab, strtab_name,
431 	    shdr)) == (Elf_Data *)S_ERROR)
432 		return;
433 
434 	if (cwd == NULL) {
435 		if ((cwd = getcwd(NULL, MAXPATHLEN)) == NULL) {
436 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_GETCWD),
437 			    in_fname, strerror(errno));
438 			return;
439 		}
440 		cwd_len = strlen(cwd);
441 	}
442 	name_len = strlen(in_fname);
443 
444 	new_size = pass1_stabindex(s_data, str_data, cwd_len, name_len);
445 
446 	if (new_size == 0)
447 		/* no changes are needed */
448 		return;
449 	/*
450 	 * The .stab.index data buffer must be updated so a new copy is
451 	 * allocated.  The original is read-only.
452 	 */
453 	if ((data = malloc(s_data->d_size)) == 0)
454 		return;
455 	(void) memcpy(data, s_data->d_buf, s_data->d_size);
456 	s_data->d_buf = data;
457 
458 	/*
459 	 * Allocate a new .stab.indexstr that is big enough to hold the new
460 	 * entries that we will need to place into it.
461 	 *
462 	 * Then append the 'cwd' onto the end of the current data.
463 	 */
464 	if ((data = malloc(str_data->d_size + new_size)) == 0)
465 		return;
466 	(void) memcpy(data, str_data->d_buf, str_data->d_size);
467 	cwd_pos = str_data->d_size;
468 	(void) strcpy((char *)data + cwd_pos, cwd);
469 	str_data->d_buf = data;
470 	str_data->d_size = str_data->d_size + new_size;
471 
472 	(void) pass2_stabindex(s_data, str_data, in_fname, name_len, cwd_pos,
473 	    cwd_pos + cwd_len + 1);
474 }
475 
476 
477 static void
478 process_stabsbfocus(Elf *elf, const char *elf_strtab,
479     const char *strtab_name, Shdr *shdr, Elf_Data *s_data,
480     const char *out_name, Half etype)
481 {
482 	Elf_Data	*str_data;
483 	struct nlist	*elem, *last = NULL;
484 	size_t		i, str_offset = 0, num_elem;
485 
486 	if ((str_data = get_str_data(elf, elf_strtab, strtab_name,
487 	    shdr)) == (Elf_Data *)S_ERROR)
488 		return;
489 
490 	num_elem = s_data->d_size / sizeof (struct nlist);
491 	for (i = 0; i < num_elem; i++) {
492 		const char	*type, *str;
493 
494 		elem = (struct nlist *)s_data->d_buf + i;
495 		switch (elem->n_type) {
496 		case 0:
497 			if (last)
498 				str_offset += last->n_value;
499 			last = elem;
500 			break;
501 		case N_BROWS:
502 			str = (char *)str_data->d_buf + elem->n_strx +
503 			    str_offset;
504 			if (etype == ET_REL)
505 				type = MSG_ORIG(MSG_STR_DASHR);
506 			else
507 				type = MSG_ORIG(MSG_STR_DASHX);
508 			sbfocus_symbol(&sb_data, out_name, type, str);
509 			break;
510 		default:
511 			/* no-op */
512 			break;
513 		}
514 	}
515 }
516 
517 
518 /* ARGSUSED2 */
519 void
520 #if	defined(_ELF64)
521 ld_start64(const char *out_name, const Half etype, const char *caller)
522 #else
523 ld_start(const char *out_name, const Half etype, const char *caller)
524 #endif
525 {
526 	out_fname = out_name;
527 	out_e_type = etype;
528 }
529 
530 
531 /* ARGSUSED1 */
532 void
533 #if	defined(_ELF64)
534 ld_file64(const char *name, const Elf_Kind kind, int flags, Elf *elf)
535 #else
536 ld_file(const char *name, const Elf_Kind kind, int flags, Elf *elf)
537 #endif
538 {
539 	in_fname = name;
540 }
541 
542 
543 /*
544  * ld_section()
545  *
546  * Args:
547  *	name	- pointer to name of current section being processed.
548  *	shdr	- pointer to Section Header of current in-file being
549  *		  processed.
550  *	s_data	- pointer to Section Data structure of current in-file
551  *		  being processed.
552  *	elf	- pointer to elf structure for current in-file being
553  *		  processed
554  */
555 /* ARGSUSED2 */
556 void
557 #if	defined(_ELF64)
558 ld_section64(const char *scn_name, Shdr *shdr, Word scnndx,
559 #else
560 ld_section(const char *scn_name, Shdr *shdr, Word scnndx,
561 #endif
562 	Elf_Data *s_data, Elf *elf)
563 {
564 	Ehdr		*ehdr;
565 	Elf_Data	*str_data;
566 	Elf_Scn		*str_scn;
567 	char		*strtab;
568 
569 	ehdr = elf_getehdr(elf);
570 	if ((ehdr->e_type != ET_DYN) && (shdr->sh_type == SHT_PROGBITS)) {
571 		/*
572 		 * this is a minor optimization for speed.  If it's not a
573 		 * stab string we aren't going to strcmp() it.
574 		 */
575 		if ((scn_name[1] == 's') &&
576 		    (scn_name[2] == 't') &&
577 		    (scn_name[3] == 'a') &&
578 		    (scn_name[4] == 'b')) {
579 			Word	shstrndx;
580 
581 			/*
582 			 * If 'extended sections' are in use, then
583 			 *	e_shstrndx == Shdr[0].sh_link
584 			 */
585 			if (ehdr->e_shstrndx == SHN_XINDEX) {
586 				Elf_Scn	*scn0;
587 				Shdr	*shdr0;
588 				scn0 = elf_getscn(elf, 0);
589 				shdr0 = elf_getshdr(scn0);
590 				shstrndx = shdr0->sh_link;
591 			} else
592 				shstrndx = ehdr->e_shstrndx;
593 
594 			str_scn = elf_getscn(elf, shstrndx);
595 			str_data = elf_getdata(str_scn, NULL);
596 			strtab = str_data->d_buf;
597 
598 			if (strcmp(scn_name, MSG_ORIG(MSG_SCN_STAB)) == 0) {
599 				/*
600 				 * Process .stab
601 				 */
602 				process_stabsbfocus(elf, strtab,
603 				    MSG_ORIG(MSG_SCN_STABSTR), shdr,
604 				    s_data, out_fname, out_e_type);
605 			} else if (strcmp(scn_name,
606 			    MSG_ORIG(MSG_SCN_STABINDEX)) == 0) {
607 				/*
608 				 * Process .stab.index
609 				 */
610 				process_stabindex(elf, strtab,
611 				    MSG_ORIG(MSG_SCN_STABINDEXSTR), shdr,
612 				    s_data);
613 			} else if (strcmp(scn_name,
614 			    MSG_ORIG(MSG_SCN_STABSBFOCUS)) == 0) {
615 				/*
616 				 * Process .stab.sbfocus
617 				 */
618 				process_stabsbfocus(elf, strtab,
619 				    MSG_ORIG(MSG_SCN_STABSBFOCUSTR), shdr,
620 				    s_data, out_fname, out_e_type);
621 			}
622 		}
623 	}
624 }
625 
626 /*
627  * Null atexit() routine, causes dlsym() to pass and thus no dlerror() message
628  * generation.
629  */
630 /* ARGSUSED */
631 void
632 #if	defined(_ELF64)
633 ld_atexit64(int status)
634 #else
635 ld_atexit(int status)
636 #endif
637 {
638 }
639 
640 #if	!defined(_ELF64)
641 /*
642  * Messaging support - funnel everything through dgettext().
643  */
644 
645 const char *
646 _libldstab_msg(Msg mid)
647 {
648 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
649 }
650 #endif
651