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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #include	<stdio.h>
27 #include	"msg.h"
28 #include	"_debug.h"
29 #include	"libld.h"
30 #include	"_string_table.h"
31 
32 /*
33  * Format an input section descriptor name for output, in the format
34  *	[ndx]name
35  * If possible, a user supplied fixed size buffer is used. Failing that,
36  * dynamic memory is allocated, which must be freed by the caller.
37  *
38  * entry:
39  *	[dbg_fmt_isec_name2]: name, scnndx  - Name and section index
40  *	[dbg_fmt_isec_name]: isp - Input section descriptor giving name
41  *		and index.
42  *
43  *	buf - Caller supplied buffer
44  *	alloc_mem - Address of pointer to be set to address of allocated
45  *		memory, or NULL if no memory is allocated.
46  *
47  * exit:
48  *	A pointer to the formatted string is returned. If the supplied buffer
49  *	was sufficient, *alloc_mem is set to NULL. If memory was allocated,
50  *	*alloc_mem references it. The caller must free this memory after use.
51  */
52 const char *
dbg_fmt_isec_name2(const char * name,Word scnndx,dbg_isec_name_buf_t buf,char ** alloc_mem)53 dbg_fmt_isec_name2(const char *name, Word scnndx, dbg_isec_name_buf_t buf,
54     char **alloc_mem)
55 {
56 	int	cnt;
57 
58 	/*
59 	 * If the section index is 0, it's not a real section.
60 	 * Just use the name as is.
61 	 */
62 	if (scnndx == 0) {
63 		*alloc_mem = NULL;
64 		return (name);
65 	}
66 
67 	/* Format into the fixed buffer */
68 	cnt = snprintf(buf, sizeof (dbg_isec_name_buf_t),
69 	    MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name);
70 
71 	/*
72 	 * If the name was too long, try to allocate a dynamic buffer.
73 	 * Failing that, fall through and use the clipped one already
74 	 * formatted into buf, as that's better than nothing.
75 	 */
76 	if ((cnt >= sizeof (dbg_isec_name_buf_t)) &&
77 	    ((*alloc_mem = malloc(cnt + 1)) != NULL)) {
78 		(void) snprintf(*alloc_mem, cnt + 1,
79 		    MSG_ORIG(MSG_FMT_ISEC_NAME), EC_WORD(scnndx), name);
80 		return (*alloc_mem);
81 	}
82 
83 	/* Return the caller supplied buffer */
84 	*alloc_mem = NULL;
85 	return (buf);
86 }
87 const char *
dbg_fmt_isec_name(Is_desc * isp,dbg_isec_name_buf_t buf,char ** alloc_mem)88 dbg_fmt_isec_name(Is_desc *isp, dbg_isec_name_buf_t buf, char **alloc_mem)
89 {
90 	return (dbg_fmt_isec_name2(isp->is_name, isp->is_scnndx, buf,
91 	    alloc_mem));
92 }
93 
94 void
Dbg_sec_strtab(Lm_list * lml,Os_desc * osp,Str_tbl * stp)95 Dbg_sec_strtab(Lm_list *lml, Os_desc *osp, Str_tbl *stp)
96 {
97 	uint_t	cnt;
98 
99 	if (DBG_NOTCLASS(DBG_C_STRTAB))
100 		return;
101 
102 	if (!osp)
103 		return;
104 
105 	Dbg_util_nl(lml, DBG_NL_STD);
106 	if (stp->st_flags & FLG_STTAB_COMPRESS)
107 		dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_COMP), osp->os_name,
108 		    EC_XWORD(stp->st_fullstrsize), EC_XWORD(stp->st_strsize));
109 	else
110 		dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_STND), osp->os_name,
111 		    EC_XWORD(stp->st_fullstrsize));
112 
113 	if ((DBG_NOTDETAIL()) ||
114 	    ((stp->st_flags & FLG_STTAB_COMPRESS) == 0))
115 		return;
116 
117 	dbg_print(lml, MSG_ORIG(MSG_STR_EMPTY));
118 	dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_HD), osp->os_name,
119 	    stp->st_hbckcnt);
120 
121 	for (cnt = 0; cnt < stp->st_hbckcnt; cnt++) {
122 		Str_hash	*strhash = stp->st_hashbcks[cnt];
123 
124 		if (strhash == NULL)
125 			continue;
126 
127 		dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_BCKT), cnt);
128 
129 		while (strhash) {
130 			size_t	stroff = strhash->hi_mstr->sm_strlen -
131 			    strhash->hi_strlen;
132 
133 			if (stroff == 0) {
134 				dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_MSTR),
135 				    EC_XWORD(strhash->hi_refcnt),
136 				    strhash->hi_mstr->sm_str);
137 			} else {
138 				dbg_print(lml, MSG_INTL(MSG_SEC_STRTAB_SUFSTR),
139 				    EC_XWORD(strhash->hi_refcnt),
140 				    &strhash->hi_mstr->sm_str[stroff],
141 				    strhash->hi_mstr->sm_str);
142 			}
143 
144 			strhash = strhash->hi_next;
145 		}
146 	}
147 }
148 
149 void
Dbg_sec_genstr_compress(Lm_list * lml,const char * os_name,Xword raw_size,Xword merge_size)150 Dbg_sec_genstr_compress(Lm_list *lml, const char *os_name,
151     Xword raw_size, Xword merge_size)
152 {
153 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
154 		return;
155 
156 	dbg_print(lml, MSG_INTL(MSG_SEC_GENSTR_COMP), os_name,
157 	    EC_XWORD(raw_size), EC_XWORD(merge_size));
158 }
159 
160 void
Dbg_sec_unsup_strmerge(Lm_list * lml,Is_desc * isp)161 Dbg_sec_unsup_strmerge(Lm_list *lml, Is_desc *isp)
162 {
163 	dbg_isec_name_buf_t	buf;
164 	char			*alloc_mem;
165 	const char		*str;
166 
167 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
168 		return;
169 
170 	/*
171 	 * We can only merge string table sections with single byte
172 	 * (char) characters. For any other (wide) character types,
173 	 * issue a message so the user will understand why these
174 	 * sections are not being picked up.
175 	 */
176 	if ((isp->is_shdr->sh_entsize > 1) ||
177 	    (isp->is_shdr->sh_addralign > 1)) {
178 		str = (isp->is_file != NULL) ? isp->is_file->ifl_name :
179 		    MSG_INTL(MSG_STR_NULL);
180 		dbg_print(lml, MSG_INTL(MSG_SEC_STRMERGE_UNSUP),
181 		    dbg_fmt_isec_name(isp, buf, &alloc_mem), str,
182 		    EC_XWORD(isp->is_shdr->sh_addralign),
183 		    EC_XWORD(isp->is_shdr->sh_entsize));
184 		if (alloc_mem != NULL)
185 			free(alloc_mem);
186 	}
187 }
188 
189 void
Dbg_sec_backing(Lm_list * lml)190 Dbg_sec_backing(Lm_list *lml)
191 {
192 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
193 		return;
194 
195 	Dbg_util_nl(lml, DBG_NL_STD);
196 	dbg_print(lml, MSG_INTL(MSG_SEC_BACKING));
197 }
198 
199 void
Dbg_sec_in(Lm_list * lml,Is_desc * isp)200 Dbg_sec_in(Lm_list *lml, Is_desc *isp)
201 {
202 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
203 		return;
204 
205 	if (isp->is_flags & FLG_IS_GNSTRMRG) {
206 		/*
207 		 * This section was generated because we have 1 or
208 		 * more SHF_MERGE|SHF_STRINGS input sections that we
209 		 * wish to merge. This new section will ultimately
210 		 * end up replacing those sections once it has been filled
211 		 * with their strings (merged and compressed) and relocations
212 		 * have been redirected.
213 		 */
214 		dbg_print(lml, MSG_INTL(MSG_SEC_INPUT_GENSTR), isp->is_name);
215 	} else if (isp->is_file == NULL) {
216 		/* Generated input section */
217 		dbg_print(lml, MSG_INTL(MSG_SEC_INPUT_GEN), isp->is_name);
218 	} else {
219 		/* Standard input section */
220 		dbg_isec_name_buf_t	buf;
221 		char			*alloc_mem;
222 
223 		dbg_print(lml, MSG_INTL(MSG_SEC_INPUT),
224 		    dbg_fmt_isec_name(isp, buf, &alloc_mem),
225 		    isp->is_file->ifl_name);
226 		if (alloc_mem != NULL)
227 			free(alloc_mem);
228 	}
229 }
230 
231 void
Dbg_sec_added(Lm_list * lml,Os_desc * osp,Sg_desc * sgp)232 Dbg_sec_added(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
233 {
234 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
235 		return;
236 
237 	dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name,
238 	    (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
239 }
240 
241 void
Dbg_sec_created(Lm_list * lml,Os_desc * osp,Sg_desc * sgp)242 Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
243 {
244 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
245 		return;
246 
247 	dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name,
248 	    (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
249 }
250 
251 void
Dbg_sec_discarded(Lm_list * lml,Is_desc * isp,Is_desc * disp)252 Dbg_sec_discarded(Lm_list *lml, Is_desc *isp, Is_desc *disp)
253 {
254 	if (DBG_NOTCLASS(DBG_C_SECTIONS | DBG_C_UNUSED))
255 		return;
256 
257 	if ((isp->is_flags & FLG_IS_INSTRMRG) &&
258 	    (disp->is_flags & FLG_IS_GNSTRMRG)) {
259 		/*
260 		 * This SHF_MERGE|SHF_STRINGS input section is being
261 		 * discarded in favor of the generated merged string section.
262 		 */
263 		dbg_isec_name_buf_t	buf;
264 		char			*alloc_mem;
265 
266 		dbg_print(lml, MSG_INTL(MSG_SEC_STRMERGE_DISCARDED),
267 		    dbg_fmt_isec_name(isp, buf, &alloc_mem),
268 		    isp->is_file->ifl_name);
269 		if (alloc_mem != NULL)
270 			free(alloc_mem);
271 	} else {
272 		/* Generic section discard */
273 		dbg_isec_name_buf_t	buf1, buf2;
274 		char			*alloc_mem1, *alloc_mem2;
275 
276 		dbg_print(lml, MSG_INTL(MSG_SEC_DISCARDED),
277 		    dbg_fmt_isec_name(isp, buf1, &alloc_mem1),
278 		    isp->is_file->ifl_name,
279 		    dbg_fmt_isec_name(disp, buf2, &alloc_mem2),
280 		    disp->is_file->ifl_name);
281 		if (alloc_mem1 != NULL)
282 			free(alloc_mem1);
283 		if (alloc_mem2 != NULL)
284 			free(alloc_mem2);
285 	}
286 }
287 
288 void
Dbg_sec_group(Lm_list * lml,Is_desc * isp,Group_desc * gdp)289 Dbg_sec_group(Lm_list *lml, Is_desc *isp, Group_desc *gdp)
290 {
291 	dbg_isec_name_buf_t	buf;
292 	char			*alloc_mem;
293 	const char		*comdat, *isp_str;
294 
295 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
296 		return;
297 
298 	if (gdp->gd_data[0] & GRP_COMDAT)
299 		comdat = MSG_ORIG(MSG_STR_COMDAT);
300 	else
301 		comdat = MSG_ORIG(MSG_STR_EMPTY);
302 
303 	isp_str = dbg_fmt_isec_name(isp, buf, &alloc_mem);
304 
305 	if (isp->is_shdr->sh_type == SHT_GROUP) {
306 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DEFINE), isp_str,
307 		    isp->is_file->ifl_name, comdat, gdp->gd_name);
308 	} else {
309 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_MEMBER), isp_str,
310 		    isp->is_file->ifl_name, comdat, gdp->gd_name);
311 	}
312 
313 	if (gdp->gd_oisc) {
314 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DISCARDED), isp_str,
315 		    isp->is_file->ifl_name, gdp->gd_name,
316 		    gdp->gd_oisc->is_file->ifl_name);
317 	}
318 
319 	if (alloc_mem != NULL)
320 		free(alloc_mem);
321 }
322 
323 void
Dbg_sec_order_list(Ofl_desc * ofl,int flag)324 Dbg_sec_order_list(Ofl_desc *ofl, int flag)
325 {
326 	Os_desc		*osp;
327 	Is_desc		*isp1;
328 	Aliste		idx1;
329 	Lm_list		*lml = ofl->ofl_lml;
330 	const char	*str;
331 
332 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
333 		return;
334 	if (DBG_NOTDETAIL())
335 		return;
336 
337 	Dbg_util_nl(lml, DBG_NL_STD);
338 
339 	/*
340 	 * If the flag == 0, then the routine is called before sorting.
341 	 */
342 	if (flag == 0)
343 		str = MSG_INTL(MSG_ORD_SORT_BEFORE);
344 	else
345 		str = MSG_INTL(MSG_ORD_SORT_AFTER);
346 
347 	for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) {
348 		int		os_isdescs_idx;
349 		Aliste		idx2;
350 
351 		Dbg_util_nl(lml, DBG_NL_STD);
352 		dbg_print(lml, str, osp->os_name);
353 		dbg_print(lml, MSG_INTL(MSG_ORD_HDR_1),
354 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_BEFORE])),
355 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_ORDERED])),
356 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_DEFAULT])),
357 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_AFTER])));
358 
359 		OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp1) {
360 			dbg_isec_name_buf_t	buf;
361 			char			*alloc_mem;
362 			const char		*isp1_str;
363 			Word			link;
364 			Ifl_desc		*ifl = isp1->is_file;
365 			Is_desc			*isp2;
366 			const char		*msg;
367 
368 			/*
369 			 * An output segment that requires ordering might have
370 			 * as little as two sorted input sections.  For example,
371 			 * the crt's can provide a SHN_BEGIN and SHN_AFTER, and
372 			 * only these two sections must be processed.  Thus, if
373 			 * a input section is unordered, move on.  Diagnosing
374 			 * any unsorted section can produce way too much noise.
375 			 */
376 			if ((isp1->is_flags & FLG_IS_ORDERED) == 0)
377 				continue;
378 
379 			if (isp1->is_shdr->sh_flags & SHF_ORDERED) {
380 				link = isp1->is_shdr->sh_info;
381 				msg = MSG_ORIG(MSG_SH_INFO);
382 			} else {	/* SHF_LINK_ORDER */
383 				link = isp1->is_shdr->sh_link;
384 				msg = MSG_ORIG(MSG_SH_LINK);
385 			}
386 
387 			isp1_str = dbg_fmt_isec_name(isp1, buf, &alloc_mem);
388 
389 			if (link == SHN_BEFORE) {
390 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_1), msg,
391 				    isp1_str, isp1->is_file->ifl_name);
392 			} else if (link == SHN_AFTER) {
393 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_2), msg,
394 				    isp1_str, isp1->is_file->ifl_name);
395 			} else {
396 				isp2 = ifl->ifl_isdesc[link];
397 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_3),
398 				    EC_WORD(isp2->is_keyident), isp1_str,
399 				    ifl->ifl_name, msg, isp2->is_name);
400 			}
401 			if (alloc_mem != NULL)
402 				free(alloc_mem);
403 		}
404 	}
405 	Dbg_util_nl(lml, DBG_NL_STD);
406 }
407 
408 /*
409  * Error message string table.
410  */
411 static const Msg order_errors[] = {
412 	MSG_ORD_ERR_INFORANGE,		/* MSG_INTL(MSG_ORD_ERR_INFORANGE) */
413 	MSG_ORD_ERR_ORDER,		/* MSG_INTL(MSG_ORD_ERR_ORDER) */
414 	MSG_ORD_ERR_LINKRANGE,		/* MSG_INTL(MSG_ORD_ERR_LINKRANGE) */
415 	MSG_ORD_ERR_FLAGS,		/* MSG_INTL(MSG_ORD_ERR_FLAGS) */
416 	MSG_ORD_ERR_CYCLIC,		/* MSG_INTL(MSG_ORD_ERR_CYCLIC) */
417 	MSG_ORD_ERR_LINKINV		/* MSG_INTL(MSG_ORD_ERR_LINKINV) */
418 };
419 
420 void
Dbg_sec_order_error(Lm_list * lml,Ifl_desc * ifl,Word ndx,int error)421 Dbg_sec_order_error(Lm_list *lml, Ifl_desc *ifl, Word ndx, int error)
422 {
423 	dbg_isec_name_buf_t	buf;
424 	char			*alloc_mem;
425 
426 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
427 		return;
428 	if (DBG_NOTDETAIL())
429 		return;
430 
431 	if (error == 0)
432 		return;
433 
434 	dbg_print(lml, MSG_INTL(MSG_ORD_ERR_TITLE),
435 	    dbg_fmt_isec_name(ifl->ifl_isdesc[ndx], buf, &alloc_mem),
436 	    ifl->ifl_name);
437 	if (alloc_mem != NULL)
438 		free(alloc_mem);
439 
440 	if (error)
441 		dbg_print(lml, MSG_INTL(order_errors[error - 1]));
442 }
443 
444 void
Dbg_sec_redirected(Lm_list * lml,Is_desc * isp,const char * nname)445 Dbg_sec_redirected(Lm_list *lml, Is_desc *isp, const char *nname)
446 {
447 	dbg_isec_name_buf_t	buf;
448 	char			*alloc_mem;
449 
450 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
451 		return;
452 
453 	dbg_print(lml, MSG_INTL(MSG_SEC_REDIRECTED),
454 	    dbg_fmt_isec_name(isp, buf, &alloc_mem), nname);
455 	if (alloc_mem != NULL)
456 		free(alloc_mem);
457 }
458 
459 void
Dbg_sec_gnu_comdat(Lm_list * lml,Is_desc * isp,Boolean comdat,Boolean relax)460 Dbg_sec_gnu_comdat(Lm_list *lml, Is_desc *isp, Boolean comdat, Boolean relax)
461 {
462 	dbg_isec_name_buf_t	buf;
463 	char			*alloc_mem;
464 	const char		*fmt;
465 
466 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
467 		return;
468 
469 	if (comdat && relax)
470 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_1);
471 	else if (comdat)
472 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_2);
473 	else
474 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_3);
475 
476 	dbg_print(lml, fmt, dbg_fmt_isec_name(isp, buf, &alloc_mem));
477 	if (alloc_mem != NULL)
478 		free(alloc_mem);
479 }
480