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