xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/symbols.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 
27 /*
28  * String conversion routines for symbol attributes.
29  */
30 #include	<stdio.h>
31 #include	<sys/elf_SPARC.h>
32 #include	<sys/elf_amd64.h>
33 #include	"_conv.h"
34 #include	"symbols_msg.h"
35 
36 const char *
37 conv_sym_other(uchar_t other, Conv_inv_buf_t *inv_buf)
38 {
39 	static const char	visibility[7] = {
40 		'D',	/* STV_DEFAULT */
41 		'I',	/* STV_INTERNAL */
42 		'H',	/* STV_HIDDEN */
43 		'P',	/* STV_PROTECTED */
44 		'X',	/* STV_EXPORTED */
45 		'S',	/* STV_SINGLETON */
46 		'E'	/* STV_ELIMINATE */
47 	};
48 	uchar_t		vis = ELF_ST_VISIBILITY(other);
49 	uint_t		ndx = 0;
50 
51 	inv_buf->buf[ndx++] = visibility[vis];
52 
53 	/*
54 	 * If unknown bits are present in st_other - throw out a '?'
55 	 */
56 	if (other & ~MSK_SYM_VISIBILITY)
57 		inv_buf->buf[ndx++] = '?';
58 	inv_buf->buf[ndx++] = '\0';
59 
60 	return (inv_buf->buf);
61 }
62 
63 static const conv_ds_t **
64 conv_sym_other_vis_strings(Conv_fmt_flags_t fmt_flags)
65 {
66 	static const Msg	vis_def[] = {
67 		MSG_STV_DEFAULT_DEF,	MSG_STV_INTERNAL_DEF,
68 		MSG_STV_HIDDEN_DEF,	MSG_STV_PROTECTED_DEF,
69 		MSG_STV_EXPORTED_DEF,	MSG_STV_SINGLETON_DEF,
70 		MSG_STV_ELIMINATE_DEF
71 	};
72 	static const Msg	vis_cf[] = {
73 		MSG_STV_DEFAULT_CF,	MSG_STV_INTERNAL_CF,
74 		MSG_STV_HIDDEN_CF,	MSG_STV_PROTECTED_CF,
75 		MSG_STV_EXPORTED_CF,	MSG_STV_SINGLETON_CF,
76 		MSG_STV_ELIMINATE_CF
77 	};
78 	static const Msg	vis_nf[] = {
79 		MSG_STV_DEFAULT_NF,	MSG_STV_INTERNAL_NF,
80 		MSG_STV_HIDDEN_NF,	MSG_STV_PROTECTED_NF,
81 		MSG_STV_EXPORTED_NF,	MSG_STV_SINGLETON_NF,
82 		MSG_STV_ELIMINATE_NF
83 	};
84 	static const conv_ds_msg_t ds_vis_def = {
85 	    CONV_DS_MSG_INIT(STV_DEFAULT, vis_def) };
86 	static const conv_ds_msg_t ds_vis_cf = {
87 	    CONV_DS_MSG_INIT(STV_DEFAULT, vis_cf) };
88 	static const conv_ds_msg_t ds_vis_nf = {
89 	    CONV_DS_MSG_INIT(STV_DEFAULT, vis_nf) };
90 
91 	/* Build NULL terminated return arrays for each string style */
92 	static const conv_ds_t	*ds_def[] = {
93 		CONV_DS_ADDR(ds_vis_def), NULL };
94 	static const conv_ds_t	*ds_cf[] = {
95 		CONV_DS_ADDR(ds_vis_cf), NULL };
96 	static const conv_ds_t	*ds_nf[] = {
97 		CONV_DS_ADDR(ds_vis_nf), NULL };
98 
99 	/* Select the strings to use */
100 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
101 	case CONV_FMT_ALT_CF:
102 		return (ds_cf);
103 	case CONV_FMT_ALT_NF:
104 		return (ds_nf);
105 	}
106 
107 	return (ds_def);
108 }
109 
110 const char *
111 conv_sym_other_vis(uchar_t value, Conv_fmt_flags_t fmt_flags,
112     Conv_inv_buf_t *inv_buf)
113 {
114 	return (conv_map_ds(ELFOSABI_NONE, EM_NONE, value,
115 	    conv_sym_other_vis_strings(fmt_flags), fmt_flags, inv_buf));
116 }
117 
118 conv_iter_ret_t
119 conv_iter_sym_other_vis(Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func,
120     void *uvalue)
121 {
122 	return (conv_iter_ds(ELFOSABI_NONE, EM_NONE,
123 	    conv_sym_other_vis_strings(fmt_flags), func, uvalue));
124 }
125 
126 static const conv_ds_t **
127 conv_sym_info_type_strings(Half mach, Conv_fmt_flags_t fmt_flags)
128 {
129 	/*
130 	 * This routine can return an array with 1 generic array, and
131 	 * a machine array, plus the NULL termination.
132 	 */
133 #define	MAX_RET	3
134 
135 	static const Msg	types_def[] = {
136 		MSG_STT_NOTYPE_DEF,	MSG_STT_OBJECT_DEF,
137 		MSG_STT_FUNC_DEF,	MSG_STT_SECTION_DEF,
138 		MSG_STT_FILE_DEF,	MSG_STT_COMMON_DEF,
139 		MSG_STT_TLS_DEF,	MSG_STT_IFUNC_DEF
140 	};
141 	static const Msg	types_cf[] = {
142 		MSG_STT_NOTYPE_CF,	MSG_STT_OBJECT_CF,
143 		MSG_STT_FUNC_CF,	MSG_STT_SECTION_CF,
144 		MSG_STT_FILE_CF,	MSG_STT_COMMON_CF,
145 		MSG_STT_TLS_CF,		MSG_STT_IFUNC_CF
146 	};
147 	static const Msg	types_cfnp[] = {
148 		MSG_STT_NOTYPE_CFNP,	MSG_STT_OBJECT_CFNP,
149 		MSG_STT_FUNC_CFNP,	MSG_STT_SECTION_CFNP,
150 		MSG_STT_FILE_CFNP,	MSG_STT_COMMON_CFNP,
151 		MSG_STT_TLS_CFNP,		MSG_STT_IFUNC_CFNP
152 	};
153 	static const Msg	types_nf[] = {
154 		MSG_STT_NOTYPE_NF,	MSG_STT_OBJECT_NF,
155 		MSG_STT_FUNC_NF,	MSG_STT_SECTION_NF,
156 		MSG_STT_FILE_NF,	MSG_STT_COMMON_NF,
157 		MSG_STT_TLS_NF,		MSG_STT_IFUNC_NF
158 	};
159 	static const conv_ds_msg_t ds_types_def = {
160 	    CONV_DS_MSG_INIT(STT_NOTYPE, types_def) };
161 	static const conv_ds_msg_t ds_types_cf = {
162 	    CONV_DS_MSG_INIT(STT_NOTYPE, types_cf) };
163 	static const conv_ds_msg_t ds_types_cfnp = {
164 	    CONV_DS_MSG_INIT(STT_NOTYPE, types_cfnp) };
165 	static const conv_ds_msg_t ds_types_nf = {
166 	    CONV_DS_MSG_INIT(STT_NOTYPE, types_nf) };
167 
168 
169 	static const Msg	sparc_def[] = { MSG_STT_SPARC_REGISTER_DEF };
170 	static const Msg	sparc_cf[] = { MSG_STT_SPARC_REGISTER_CF };
171 	static const Msg	sparc_cfnp[] = { MSG_STT_SPARC_REGISTER_CFNP };
172 	static const Msg	sparc_nf[] = { MSG_STT_SPARC_REGISTER_NF };
173 	static const conv_ds_msg_t ds_sparc_def = {
174 	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_def) };
175 	static const conv_ds_msg_t ds_sparc_cf = {
176 	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_cf) };
177 	static const conv_ds_msg_t ds_sparc_cfnp = {
178 	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_cfnp) };
179 	static const conv_ds_msg_t ds_sparc_nf = {
180 	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_nf) };
181 
182 
183 	static const conv_ds_t	*retarr[MAX_RET];
184 
185 	int	retndx = 0;
186 	int	is_sparc;
187 
188 	is_sparc = (mach == EM_SPARC) || (mach == EM_SPARCV9) ||
189 	    (mach == EM_SPARC32PLUS) || (mach == CONV_MACH_ALL);
190 
191 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
192 	case CONV_FMT_ALT_CF:
193 		retarr[retndx++] = CONV_DS_ADDR(ds_types_cf);
194 		if (is_sparc)
195 			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_cf);
196 		break;
197 	case CONV_FMT_ALT_CFNP:
198 		retarr[retndx++] = CONV_DS_ADDR(ds_types_cfnp);
199 		if (is_sparc)
200 			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_cfnp);
201 		break;
202 	case CONV_FMT_ALT_NF:
203 		retarr[retndx++] = CONV_DS_ADDR(ds_types_nf);
204 		if (is_sparc)
205 			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_nf);
206 		break;
207 	default:
208 		retarr[retndx++] = CONV_DS_ADDR(ds_types_def);
209 		if (is_sparc)
210 			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_def);
211 		break;
212 	}
213 
214 	retarr[retndx++] = NULL;
215 	assert(retndx <= MAX_RET);
216 	return (retarr);
217 }
218 
219 const char *
220 conv_sym_info_type(Half mach, uchar_t type, Conv_fmt_flags_t fmt_flags,
221     Conv_inv_buf_t *inv_buf)
222 {
223 	return (conv_map_ds(ELFOSABI_NONE, mach, type,
224 	    conv_sym_info_type_strings(mach, fmt_flags), fmt_flags, inv_buf));
225 }
226 
227 conv_iter_ret_t
228 conv_iter_sym_info_type(Half mach, Conv_fmt_flags_t fmt_flags,
229     conv_iter_cb_t func, void *uvalue)
230 {
231 	return (conv_iter_ds(ELFOSABI_NONE, mach,
232 	    conv_sym_info_type_strings(mach, fmt_flags), func, uvalue));
233 }
234 
235 static const conv_ds_t **
236 conv_sym_info_bind_strings(Conv_fmt_flags_t fmt_flags)
237 {
238 	static const Msg	binds_def[] = {
239 		MSG_STB_LOCAL_DEF,	MSG_STB_GLOBAL_DEF,
240 		MSG_STB_WEAK_DEF
241 	};
242 	static const Msg	binds_cf[] = {
243 		MSG_STB_LOCAL_CF,	MSG_STB_GLOBAL_CF,
244 		MSG_STB_WEAK_CF
245 	};
246 	static const Msg	binds_cfnp[] = {
247 		MSG_STB_LOCAL_CFNP,	MSG_STB_GLOBAL_CFNP,
248 		MSG_STB_WEAK_CFNP
249 	};
250 	static const Msg	binds_nf[] = {
251 		MSG_STB_LOCAL_NF,	MSG_STB_GLOBAL_NF,
252 		MSG_STB_WEAK_NF
253 	};
254 	static const conv_ds_msg_t ds_binds_def = {
255 	    CONV_DS_MSG_INIT(STB_LOCAL, binds_def) };
256 	static const conv_ds_msg_t ds_binds_cf = {
257 	    CONV_DS_MSG_INIT(STB_LOCAL, binds_cf) };
258 	static const conv_ds_msg_t ds_binds_cfnp = {
259 	    CONV_DS_MSG_INIT(STB_LOCAL, binds_cfnp) };
260 	static const conv_ds_msg_t ds_binds_nf = {
261 	    CONV_DS_MSG_INIT(STB_LOCAL, binds_nf) };
262 
263 
264 	/* Build NULL terminated return arrays for each string style */
265 	static const conv_ds_t	*ds_def[] = {
266 		CONV_DS_ADDR(ds_binds_def), NULL };
267 	static const conv_ds_t	*ds_cf[] = {
268 		CONV_DS_ADDR(ds_binds_cf), NULL };
269 	static const conv_ds_t	*ds_cfnp[] = {
270 		CONV_DS_ADDR(ds_binds_cfnp), NULL };
271 	static const conv_ds_t	*ds_nf[] = {
272 		CONV_DS_ADDR(ds_binds_nf), NULL };
273 
274 
275 	/* Select the strings to use */
276 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
277 	case CONV_FMT_ALT_CF:
278 		return (ds_cf);
279 	case CONV_FMT_ALT_CFNP:
280 		return (ds_cfnp);
281 	case CONV_FMT_ALT_NF:
282 		return (ds_nf);
283 	}
284 
285 	return (ds_def);
286 }
287 
288 const char *
289 conv_sym_info_bind(uchar_t bind, Conv_fmt_flags_t fmt_flags,
290     Conv_inv_buf_t *inv_buf)
291 {
292 	return (conv_map_ds(ELFOSABI_NONE, EM_NONE, bind,
293 	    conv_sym_info_bind_strings(fmt_flags), fmt_flags, inv_buf));
294 }
295 
296 conv_iter_ret_t
297 conv_iter_sym_info_bind(Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func,
298     void *uvalue)
299 {
300 	return (conv_iter_ds(ELFOSABI_NONE, EM_NONE,
301 	    conv_sym_info_bind_strings(fmt_flags), func, uvalue));
302 }
303 
304 static const conv_ds_t **
305 conv_sym_shndx_strings(Conv_fmt_flags_t fmt_flags)
306 {
307 #define	ALL	ELFOSABI_NONE, EM_NONE
308 #define	SOL	ELFOSABI_SOLARIS, EM_NONE
309 #define	AMD	ELFOSABI_NONE, EM_AMD64
310 
311 	/*
312 	 * There aren't many of these values, and they are sparse,
313 	 * so rather than separate them into different ranges, I use
314 	 * a single Val_desc2 array for all of them.
315 	 */
316 	static const Val_desc2 shn_def[] = {
317 		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CFNP },
318 		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CFNP },
319 		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CFNP },
320 		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_DEF },
321 		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_DEF },
322 		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CFNP },
323 		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CFNP },
324 		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CFNP },
325 		{ 0 }
326 	};
327 	static const Val_desc2 shn_cf[] = {
328 		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CF },
329 		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CF },
330 		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CF },
331 		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_CF },
332 		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_CF },
333 		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CF },
334 		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CF },
335 		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CF },
336 		{ 0 }
337 	};
338 	static const Val_desc2 shn_cfnp[] = {
339 		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CFNP },
340 		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CFNP },
341 		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CFNP },
342 		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_CFNP },
343 		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_CFNP },
344 		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CFNP },
345 		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CFNP },
346 		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CFNP },
347 		{ 0 }
348 	};
349 	static const Val_desc2 shn_nf[] = {
350 		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_NF },
351 		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_NF },
352 		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_NF },
353 		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_NF },
354 		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_NF },
355 		{ SHN_ABS,		ALL,	MSG_SHN_ABS_NF },
356 		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_NF },
357 		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_NF },
358 		{ 0 }
359 	};
360 	static const conv_ds_vd2_t ds_shn_def = {
361 	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_def };
362 	static const conv_ds_vd2_t ds_shn_cf = {
363 	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_cf };
364 	static const conv_ds_vd2_t ds_shn_cfnp = {
365 	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_cfnp };
366 	static const conv_ds_vd2_t ds_shn_nf = {
367 	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_nf };
368 
369 	/* Build NULL terminated return arrays for each string style */
370 	static const conv_ds_t	*ds_def[] = {
371 		CONV_DS_ADDR(ds_shn_def), NULL };
372 	static const conv_ds_t	*ds_cf[] = {
373 		CONV_DS_ADDR(ds_shn_cf), NULL };
374 	static const conv_ds_t	*ds_cfnp[] = {
375 		CONV_DS_ADDR(ds_shn_cfnp), NULL };
376 	static const conv_ds_t	*ds_nf[] = {
377 		CONV_DS_ADDR(ds_shn_nf), NULL };
378 
379 	/* Select the strings to use */
380 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
381 	case CONV_FMT_ALT_CF:
382 		return (ds_cf);
383 	case CONV_FMT_ALT_CFNP:
384 		return (ds_cfnp);
385 	case CONV_FMT_ALT_NF:
386 		return (ds_nf);
387 	}
388 
389 	return (ds_def);
390 
391 #undef ALL
392 #undef SOL
393 #undef AMD
394 }
395 
396 const char *
397 conv_sym_shndx(uchar_t osabi, Half mach, Half shndx, Conv_fmt_flags_t fmt_flags,
398     Conv_inv_buf_t *inv_buf)
399 {
400 	return (conv_map_ds(osabi, mach, shndx,
401 	    conv_sym_shndx_strings(fmt_flags), fmt_flags, inv_buf));
402 }
403 
404 conv_iter_ret_t
405 conv_iter_sym_shndx(conv_iter_osabi_t osabi, Half mach,
406     Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func, void *uvalue)
407 {
408 	static const Msg amd64_alias_cf[] = { MSG_SHN_X86_64_LCOMMON_CF };
409 	static const conv_ds_msg_t ds_msg_amd64_alias_cf = {
410 	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_cf) };
411 	static const conv_ds_t	*ds_amd64_alias_cf[] = {
412 	    CONV_DS_ADDR(ds_msg_amd64_alias_cf), NULL };
413 
414 	static const Msg amd64_alias_cfnp[] = { MSG_SHN_X86_64_LCOMMON_CFNP };
415 	static const conv_ds_msg_t ds_msg_amd64_alias_cfnp = {
416 	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_cfnp) };
417 	static const conv_ds_t	*ds_amd64_alias_cfnp[] = {
418 	    CONV_DS_ADDR(ds_msg_amd64_alias_cfnp), NULL };
419 
420 	static const Msg amd64_alias_nf[] = { MSG_SHN_X86_64_LCOMMON_NF };
421 	static const conv_ds_msg_t ds_msg_amd64_alias_nf = {
422 	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_nf) };
423 	static const conv_ds_t	*ds_amd64_alias_nf[] = {
424 	    CONV_DS_ADDR(ds_msg_amd64_alias_nf), NULL };
425 
426 
427 	if (conv_iter_ds(osabi, mach, conv_sym_shndx_strings(fmt_flags),
428 	    func, uvalue) == CONV_ITER_DONE)
429 		return (CONV_ITER_DONE);
430 
431 	/*
432 	 * SHN_AMD64_LCOMMON is also known as SHN_X86_64_LCOMMON
433 	 */
434 	if (mach == EM_AMD64) {
435 		const conv_ds_t	**ds;
436 
437 		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
438 		case CONV_FMT_ALT_CF:
439 			ds = ds_amd64_alias_cf;
440 			break;
441 		case CONV_FMT_ALT_NF:
442 			ds = ds_amd64_alias_nf;
443 			break;
444 		default:
445 			ds = ds_amd64_alias_cfnp;
446 			break;
447 		}
448 		return (conv_iter_ds(ELFOSABI_NONE, mach, ds, func, uvalue));
449 	}
450 
451 	return (CONV_ITER_CONT);
452 }
453