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
36const char *
37conv_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
63static const conv_ds_t **
64conv_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
110const char *
111conv_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
118conv_iter_ret_t
119conv_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
126static const conv_ds_t **
127conv_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_nf[] = {
148		MSG_STT_NOTYPE_NF,	MSG_STT_OBJECT_NF,
149		MSG_STT_FUNC_NF,	MSG_STT_SECTION_NF,
150		MSG_STT_FILE_NF,	MSG_STT_COMMON_NF,
151		MSG_STT_TLS_NF,		MSG_STT_IFUNC_NF
152	};
153	static const conv_ds_msg_t ds_types_def = {
154	    CONV_DS_MSG_INIT(STT_NOTYPE, types_def) };
155	static const conv_ds_msg_t ds_types_cf = {
156	    CONV_DS_MSG_INIT(STT_NOTYPE, types_cf) };
157	static const conv_ds_msg_t ds_types_nf = {
158	    CONV_DS_MSG_INIT(STT_NOTYPE, types_nf) };
159
160
161	static const Msg	sparc_def[] = { MSG_STT_SPARC_REGISTER_DEF };
162	static const Msg	sparc_cf[] = { MSG_STT_SPARC_REGISTER_CF };
163	static const Msg	sparc_nf[] = { MSG_STT_SPARC_REGISTER_NF };
164	static const conv_ds_msg_t ds_sparc_def = {
165	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_def) };
166	static const conv_ds_msg_t ds_sparc_cf = {
167	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_cf) };
168	static const conv_ds_msg_t ds_sparc_nf = {
169	    CONV_DS_MSG_INIT(STT_SPARC_REGISTER, sparc_nf) };
170
171
172	static const conv_ds_t	*retarr[MAX_RET];
173
174	int	retndx = 0;
175	int	is_sparc;
176
177	is_sparc = (mach == EM_SPARC) || (mach == EM_SPARCV9) ||
178	    (mach == EM_SPARC32PLUS) || (mach == CONV_MACH_ALL);
179
180	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
181	case CONV_FMT_ALT_CF:
182		retarr[retndx++] = CONV_DS_ADDR(ds_types_cf);
183		if (is_sparc)
184			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_cf);
185		break;
186	case CONV_FMT_ALT_NF:
187		retarr[retndx++] = CONV_DS_ADDR(ds_types_nf);
188		if (is_sparc)
189			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_nf);
190		break;
191	default:
192		retarr[retndx++] = CONV_DS_ADDR(ds_types_def);
193		if (is_sparc)
194			retarr[retndx++] = CONV_DS_ADDR(ds_sparc_def);
195		break;
196	}
197
198	retarr[retndx++] = NULL;
199	assert(retndx <= MAX_RET);
200	return (retarr);
201}
202
203const char *
204conv_sym_info_type(Half mach, uchar_t type, Conv_fmt_flags_t fmt_flags,
205    Conv_inv_buf_t *inv_buf)
206{
207	return (conv_map_ds(ELFOSABI_NONE, mach, type,
208	    conv_sym_info_type_strings(mach, fmt_flags), fmt_flags, inv_buf));
209}
210
211conv_iter_ret_t
212conv_iter_sym_info_type(Half mach, Conv_fmt_flags_t fmt_flags,
213    conv_iter_cb_t func, void *uvalue)
214{
215	return (conv_iter_ds(ELFOSABI_NONE, mach,
216	    conv_sym_info_type_strings(mach, fmt_flags), func, uvalue));
217}
218
219static const conv_ds_t **
220conv_sym_info_bind_strings(Conv_fmt_flags_t fmt_flags)
221{
222	static const Msg	binds_def[] = {
223		MSG_STB_LOCAL_DEF,	MSG_STB_GLOBAL_DEF,
224		MSG_STB_WEAK_DEF
225	};
226	static const Msg	binds_cf[] = {
227		MSG_STB_LOCAL_CF,	MSG_STB_GLOBAL_CF,
228		MSG_STB_WEAK_CF
229	};
230	static const Msg	binds_nf[] = {
231		MSG_STB_LOCAL_NF,	MSG_STB_GLOBAL_NF,
232		MSG_STB_WEAK_NF
233	};
234	static const conv_ds_msg_t ds_binds_def = {
235	    CONV_DS_MSG_INIT(STB_LOCAL, binds_def) };
236	static const conv_ds_msg_t ds_binds_cf = {
237	    CONV_DS_MSG_INIT(STB_LOCAL, binds_cf) };
238	static const conv_ds_msg_t ds_binds_nf = {
239	    CONV_DS_MSG_INIT(STB_LOCAL, binds_nf) };
240
241
242	/* Build NULL terminated return arrays for each string style */
243	static const conv_ds_t	*ds_def[] = {
244		CONV_DS_ADDR(ds_binds_def), NULL };
245	static const conv_ds_t	*ds_cf[] = {
246		CONV_DS_ADDR(ds_binds_cf), NULL };
247	static const conv_ds_t	*ds_nf[] = {
248		CONV_DS_ADDR(ds_binds_nf), NULL };
249
250
251	/* Select the strings to use */
252	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
253	case CONV_FMT_ALT_CF:
254		return (ds_cf);
255	case CONV_FMT_ALT_NF:
256		return (ds_nf);
257	}
258
259	return (ds_def);
260}
261
262const char *
263conv_sym_info_bind(uchar_t bind, Conv_fmt_flags_t fmt_flags,
264    Conv_inv_buf_t *inv_buf)
265{
266	return (conv_map_ds(ELFOSABI_NONE, EM_NONE, bind,
267	    conv_sym_info_bind_strings(fmt_flags), fmt_flags, inv_buf));
268}
269
270conv_iter_ret_t
271conv_iter_sym_info_bind(Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func,
272    void *uvalue)
273{
274	return (conv_iter_ds(ELFOSABI_NONE, EM_NONE,
275	    conv_sym_info_bind_strings(fmt_flags), func, uvalue));
276}
277
278static const conv_ds_t **
279conv_sym_shndx_strings(Conv_fmt_flags_t fmt_flags)
280{
281#define	ALL	ELFOSABI_NONE, EM_NONE
282#define	SOL	ELFOSABI_SOLARIS, EM_NONE
283#define	AMD	ELFOSABI_NONE, EM_AMD64
284
285	/*
286	 * There aren't many of these values, and they are sparse,
287	 * so rather than separate them into different ranges, I use
288	 * a single Val_desc2 array for all of them.
289	 */
290	static const Val_desc2 shn_def[] = {
291		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CFNP },
292		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CFNP },
293		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CFNP },
294		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_DEF },
295		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_DEF },
296		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CFNP },
297		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CFNP },
298		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CFNP },
299		{ 0 }
300	};
301	static const Val_desc2 shn_cf[] = {
302		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CF },
303		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CF },
304		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CF },
305		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_CF },
306		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_CF },
307		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CF },
308		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CF },
309		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CF },
310		{ 0 }
311	};
312	static const Val_desc2 shn_cfnp[] = {
313		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_CFNP },
314		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_CFNP },
315		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_CFNP },
316		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_CFNP },
317		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_CFNP },
318		{ SHN_ABS,		ALL,	MSG_SHN_ABS_CFNP },
319		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_CFNP },
320		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_CFNP },
321		{ 0 }
322	};
323	static const Val_desc2 shn_nf[] = {
324		{ SHN_UNDEF,		ALL,	MSG_SHN_UNDEF_NF },
325		{ SHN_BEFORE,		ALL,	MSG_SHN_BEFORE_NF },
326		{ SHN_AFTER,		ALL,	MSG_SHN_AFTER_NF },
327		{ SHN_AMD64_LCOMMON,	AMD,	MSG_SHN_AMD64_LCOMMON_NF },
328		{ SHN_SUNW_IGNORE,	SOL,	MSG_SHN_SUNW_IGNORE_NF },
329		{ SHN_ABS,		ALL,	MSG_SHN_ABS_NF },
330		{ SHN_COMMON,		ALL,	MSG_SHN_COMMON_NF },
331		{ SHN_XINDEX,		ALL,	MSG_SHN_XINDEX_NF },
332		{ 0 }
333	};
334	static const conv_ds_vd2_t ds_shn_def = {
335	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_def };
336	static const conv_ds_vd2_t ds_shn_cf = {
337	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_cf };
338	static const conv_ds_vd2_t ds_shn_cfnp = {
339	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_cfnp };
340	static const conv_ds_vd2_t ds_shn_nf = {
341	    CONV_DS_VD2, SHN_UNDEF, SHN_XINDEX, shn_nf };
342
343	/* Build NULL terminated return arrays for each string style */
344	static const conv_ds_t	*ds_def[] = {
345		CONV_DS_ADDR(ds_shn_def), NULL };
346	static const conv_ds_t	*ds_cf[] = {
347		CONV_DS_ADDR(ds_shn_cf), NULL };
348	static const conv_ds_t	*ds_cfnp[] = {
349		CONV_DS_ADDR(ds_shn_cfnp), NULL };
350	static const conv_ds_t	*ds_nf[] = {
351		CONV_DS_ADDR(ds_shn_nf), NULL };
352
353	/* Select the strings to use */
354	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
355	case CONV_FMT_ALT_CF:
356		return (ds_cf);
357	case CONV_FMT_ALT_CFNP:
358		return (ds_cfnp);
359	case CONV_FMT_ALT_NF:
360		return (ds_nf);
361	}
362
363	return (ds_def);
364
365#undef ALL
366#undef SOL
367#undef AMD
368}
369
370const char *
371conv_sym_shndx(uchar_t osabi, Half mach, Half shndx, Conv_fmt_flags_t fmt_flags,
372    Conv_inv_buf_t *inv_buf)
373{
374	return (conv_map_ds(osabi, mach, shndx,
375	    conv_sym_shndx_strings(fmt_flags), fmt_flags, inv_buf));
376}
377
378conv_iter_ret_t
379conv_iter_sym_shndx(conv_iter_osabi_t osabi, Half mach,
380    Conv_fmt_flags_t fmt_flags, conv_iter_cb_t func, void *uvalue)
381{
382	static const Msg amd64_alias_cf[] = { MSG_SHN_X86_64_LCOMMON_CF };
383	static const conv_ds_msg_t ds_msg_amd64_alias_cf = {
384	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_cf) };
385	static const conv_ds_t	*ds_amd64_alias_cf[] = {
386	    CONV_DS_ADDR(ds_msg_amd64_alias_cf), NULL };
387
388	static const Msg amd64_alias_cfnp[] = { MSG_SHN_X86_64_LCOMMON_CFNP };
389	static const conv_ds_msg_t ds_msg_amd64_alias_cfnp = {
390	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_cfnp) };
391	static const conv_ds_t	*ds_amd64_alias_cfnp[] = {
392	    CONV_DS_ADDR(ds_msg_amd64_alias_cfnp), NULL };
393
394	static const Msg amd64_alias_nf[] = { MSG_SHN_X86_64_LCOMMON_NF };
395	static const conv_ds_msg_t ds_msg_amd64_alias_nf = {
396	    CONV_DS_MSG_INIT(SHN_X86_64_LCOMMON, amd64_alias_nf) };
397	static const conv_ds_t	*ds_amd64_alias_nf[] = {
398	    CONV_DS_ADDR(ds_msg_amd64_alias_nf), NULL };
399
400
401	if (conv_iter_ds(osabi, mach, conv_sym_shndx_strings(fmt_flags),
402	    func, uvalue) == CONV_ITER_DONE)
403		return (CONV_ITER_DONE);
404
405	/*
406	 * SHN_AMD64_LCOMMON is also known as SHN_X86_64_LCOMMON
407	 */
408	if (mach == EM_AMD64) {
409		const conv_ds_t	**ds;
410
411		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
412		case CONV_FMT_ALT_CF:
413			ds = ds_amd64_alias_cf;
414			break;
415		case CONV_FMT_ALT_NF:
416			ds = ds_amd64_alias_nf;
417			break;
418		default:
419			ds = ds_amd64_alias_cfnp;
420			break;
421		}
422		return (conv_iter_ds(ELFOSABI_NONE, mach, ds, func, uvalue));
423	}
424
425	return (CONV_ITER_CONT);
426}
427