xref: /illumos-gate/usr/src/cmd/sgs/liblddbg/common/sections.c (revision 5279807d7e1818eac6f90ac640b7a89cdb37522d)
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 2009 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 *
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 *
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
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
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
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
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
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
232 Dbg_sec_added(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
233 {
234 	const char	*str;
235 
236 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
237 		return;
238 
239 	if (sgp->sg_name && *sgp->sg_name)
240 		str = sgp->sg_name;
241 	else
242 		str = MSG_INTL(MSG_STR_NULL);
243 
244 	dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name, str);
245 }
246 
247 void
248 Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
249 {
250 	const char	*str;
251 
252 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
253 		return;
254 
255 	if (sgp->sg_name && *sgp->sg_name)
256 		str = sgp->sg_name;
257 	else
258 		str = MSG_INTL(MSG_STR_NULL);
259 
260 	dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name, str);
261 }
262 
263 void
264 Dbg_sec_discarded(Lm_list *lml, Is_desc *isp, Is_desc *disp)
265 {
266 	if (DBG_NOTCLASS(DBG_C_SECTIONS | DBG_C_UNUSED))
267 		return;
268 
269 	if ((isp->is_flags & FLG_IS_INSTRMRG) &&
270 	    (disp->is_flags & FLG_IS_GNSTRMRG)) {
271 		/*
272 		 * This SHF_MERGE|SHF_STRINGS input section is being
273 		 * discarded in favor of the generated merged string section.
274 		 */
275 		dbg_isec_name_buf_t	buf;
276 		char			*alloc_mem;
277 
278 		dbg_print(lml, MSG_INTL(MSG_SEC_STRMERGE_DISCARDED),
279 		    dbg_fmt_isec_name(isp, buf, &alloc_mem),
280 		    isp->is_file->ifl_name);
281 		if (alloc_mem != NULL)
282 			free(alloc_mem);
283 	} else {
284 		/* Generic section discard */
285 		dbg_isec_name_buf_t	buf1, buf2;
286 		char			*alloc_mem1, *alloc_mem2;
287 
288 		dbg_print(lml, MSG_INTL(MSG_SEC_DISCARDED),
289 		    dbg_fmt_isec_name(isp, buf1, &alloc_mem1),
290 		    isp->is_file->ifl_name,
291 		    dbg_fmt_isec_name(disp, buf2, &alloc_mem2),
292 		    disp->is_file->ifl_name);
293 		if (alloc_mem1 != NULL)
294 			free(alloc_mem1);
295 		if (alloc_mem2 != NULL)
296 			free(alloc_mem2);
297 	}
298 }
299 
300 void
301 Dbg_sec_group(Lm_list *lml, Is_desc *isp, Group_desc *gdp)
302 {
303 	dbg_isec_name_buf_t	buf;
304 	char			*alloc_mem;
305 	const char		*comdat, *isp_str;
306 
307 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
308 		return;
309 
310 	if (gdp->gd_data[0] & GRP_COMDAT)
311 		comdat = MSG_ORIG(MSG_STR_COMDAT);
312 	else
313 		comdat = MSG_ORIG(MSG_STR_EMPTY);
314 
315 	isp_str = dbg_fmt_isec_name(isp, buf, &alloc_mem);
316 
317 	if (isp->is_shdr->sh_type == SHT_GROUP) {
318 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DEFINE), isp_str,
319 		    isp->is_file->ifl_name, comdat, gdp->gd_name);
320 	} else {
321 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_MEMBER), isp_str,
322 		    isp->is_file->ifl_name, comdat, gdp->gd_name);
323 	}
324 
325 	if (gdp->gd_oisc) {
326 		dbg_print(lml, MSG_INTL(MSG_SEC_GRP_DISCARDED), isp_str,
327 		    isp->is_file->ifl_name, gdp->gd_name,
328 		    gdp->gd_oisc->is_file->ifl_name);
329 	}
330 
331 	if (alloc_mem != NULL)
332 		free(alloc_mem);
333 }
334 
335 void
336 Dbg_sec_order_list(Ofl_desc *ofl, int flag)
337 {
338 	Os_desc		*osp;
339 	Is_desc		*isp1;
340 	Aliste		idx1;
341 	Lm_list		*lml = ofl->ofl_lml;
342 	const char	*str;
343 
344 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
345 		return;
346 	if (DBG_NOTDETAIL())
347 		return;
348 
349 	Dbg_util_nl(lml, DBG_NL_STD);
350 
351 	/*
352 	 * If the flag == 0, then the routine is called before sorting.
353 	 */
354 	if (flag == 0)
355 		str = MSG_INTL(MSG_ORD_SORT_BEFORE);
356 	else
357 		str = MSG_INTL(MSG_ORD_SORT_AFTER);
358 
359 	for (APLIST_TRAVERSE(ofl->ofl_ordered, idx1, osp)) {
360 		int		os_isdescs_idx;
361 		Aliste		idx2;
362 
363 		Dbg_util_nl(lml, DBG_NL_STD);
364 		dbg_print(lml, str, osp->os_name);
365 		dbg_print(lml, MSG_INTL(MSG_ORD_HDR_1),
366 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_BEFORE])),
367 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_ORDERED])),
368 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_DEFAULT])),
369 		    EC_WORD(aplist_nitems(osp->os_isdescs[OS_ISD_AFTER])));
370 
371 		OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp1) {
372 			dbg_isec_name_buf_t	buf;
373 			char			*alloc_mem;
374 			const char		*isp1_str;
375 			Word			link;
376 			Ifl_desc		*ifl = isp1->is_file;
377 			Is_desc			*isp2;
378 			const char		*msg;
379 
380 			/*
381 			 * An output section with sorted input sections
382 			 * can also have a large number of unsorted sections.
383 			 * Skip these without comment.
384 			 */
385 			if ((isp1->is_flags & FLG_IS_ORDERED) == 0) {
386 				continue;
387 			}
388 
389 			if (isp1->is_shdr->sh_flags & SHF_ORDERED) {
390 				link = isp1->is_shdr->sh_info;
391 				msg = MSG_ORIG(MSG_SH_INFO);
392 			} else {	/* SHF_LINK_ORDER */
393 				link = isp1->is_shdr->sh_link;
394 				msg = MSG_ORIG(MSG_SH_LINK);
395 			}
396 
397 			isp1_str = dbg_fmt_isec_name(isp1, buf, &alloc_mem);
398 
399 			if (link == SHN_BEFORE) {
400 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_1), msg,
401 				    isp1_str, isp1->is_file->ifl_name);
402 			} else if (link == SHN_AFTER) {
403 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_2), msg,
404 				    isp1_str, isp1->is_file->ifl_name);
405 			} else {
406 				isp2 = ifl->ifl_isdesc[link];
407 				dbg_print(lml, MSG_INTL(MSG_ORD_TITLE_3),
408 				    EC_WORD(isp2->is_keyident), isp1_str,
409 				    ifl->ifl_name, msg, isp2->is_name);
410 			}
411 			if (alloc_mem != NULL)
412 				free(alloc_mem);
413 		}
414 	}
415 	Dbg_util_nl(lml, DBG_NL_STD);
416 }
417 
418 /*
419  * Error message string table.
420  */
421 static const Msg order_errors[] = {
422 	MSG_ORD_ERR_INFORANGE,		/* MSG_INTL(MSG_ORD_ERR_INFORANGE) */
423 	MSG_ORD_ERR_ORDER,		/* MSG_INTL(MSG_ORD_ERR_ORDER) */
424 	MSG_ORD_ERR_LINKRANGE,		/* MSG_INTL(MSG_ORD_ERR_LINKRANGE) */
425 	MSG_ORD_ERR_FLAGS,		/* MSG_INTL(MSG_ORD_ERR_FLAGS) */
426 	MSG_ORD_ERR_CYCLIC,		/* MSG_INTL(MSG_ORD_ERR_CYCLIC) */
427 	MSG_ORD_ERR_LINKINV		/* MSG_INTL(MSG_ORD_ERR_LINKINV) */
428 };
429 
430 void
431 Dbg_sec_order_error(Lm_list *lml, Ifl_desc *ifl, Word ndx, int error)
432 {
433 	dbg_isec_name_buf_t	buf;
434 	char			*alloc_mem;
435 
436 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
437 		return;
438 	if (DBG_NOTDETAIL())
439 		return;
440 
441 	if (error == 0)
442 		return;
443 
444 	dbg_print(lml, MSG_INTL(MSG_ORD_ERR_TITLE),
445 	    dbg_fmt_isec_name(ifl->ifl_isdesc[ndx], buf, &alloc_mem),
446 	    ifl->ifl_name);
447 	if (alloc_mem != NULL)
448 		free(alloc_mem);
449 
450 	if (error)
451 		dbg_print(lml, MSG_INTL(order_errors[error - 1]));
452 }
453 
454 void
455 Dbg_sec_redirected(Lm_list *lml, Is_desc *isp, const char *nname)
456 {
457 	dbg_isec_name_buf_t	buf;
458 	char			*alloc_mem;
459 
460 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
461 		return;
462 
463 	dbg_print(lml, MSG_INTL(MSG_SEC_REDIRECTED),
464 	    dbg_fmt_isec_name(isp, buf, &alloc_mem), nname);
465 	if (alloc_mem != NULL)
466 		free(alloc_mem);
467 }
468 
469 void
470 Dbg_sec_gnu_comdat(Lm_list *lml, Is_desc *isp, uint_t comdat, uint_t relax)
471 {
472 	dbg_isec_name_buf_t	buf;
473 	char			*alloc_mem;
474 	const char		*fmt;
475 
476 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
477 		return;
478 
479 	if (comdat && relax)
480 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_1);
481 	else if (comdat)
482 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_2);
483 	else
484 		fmt = MSG_INTL(MSG_SEC_GNU_COMDAT_3);
485 
486 	dbg_print(lml, fmt, dbg_fmt_isec_name(isp, buf, &alloc_mem));
487 	if (alloc_mem != NULL)
488 		free(alloc_mem);
489 }
490