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 *
conv_sym_other(uchar_t other,Conv_inv_buf_t * inv_buf)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 **
conv_sym_other_vis_strings(Conv_fmt_flags_t fmt_flags)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 *
conv_sym_other_vis(uchar_t value,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)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
conv_iter_sym_other_vis(Conv_fmt_flags_t fmt_flags,conv_iter_cb_t func,void * uvalue)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 **
conv_sym_info_type_strings(Half mach,Conv_fmt_flags_t fmt_flags)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 *
conv_sym_info_type(Half mach,uchar_t type,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)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
conv_iter_sym_info_type(Half mach,Conv_fmt_flags_t fmt_flags,conv_iter_cb_t func,void * uvalue)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 **
conv_sym_info_bind_strings(Conv_fmt_flags_t fmt_flags)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 *
conv_sym_info_bind(uchar_t bind,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)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
conv_iter_sym_info_bind(Conv_fmt_flags_t fmt_flags,conv_iter_cb_t func,void * uvalue)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 **
conv_sym_shndx_strings(Conv_fmt_flags_t fmt_flags)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 *
conv_sym_shndx(uchar_t osabi,Half mach,Half shndx,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)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
conv_iter_sym_shndx(conv_iter_osabi_t osabi,Half mach,Conv_fmt_flags_t fmt_flags,conv_iter_cb_t func,void * uvalue)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