Home | History | Annotate | Download | only in common
      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 const conv_ds_t	*ds_def[] = {
     93 		CONV_DS_ADDR(ds_vis_def), NULL };
     94 	static const const conv_ds_t	*ds_cf[] = {
     95 		CONV_DS_ADDR(ds_vis_cf), NULL };
     96 	static const 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_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 
    203 const char *
    204 conv_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 
    211 conv_iter_ret_t
    212 conv_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 
    219 static const conv_ds_t **
    220 conv_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 const conv_ds_t	*ds_def[] = {
    244 		CONV_DS_ADDR(ds_binds_def), NULL };
    245 	static const const conv_ds_t	*ds_cf[] = {
    246 		CONV_DS_ADDR(ds_binds_cf), NULL };
    247 	static const 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 
    262 const char *
    263 conv_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 
    270 conv_iter_ret_t
    271 conv_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 
    278 static const conv_ds_t **
    279 conv_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 const conv_ds_t	*ds_def[] = {
    345 		CONV_DS_ADDR(ds_shn_def), NULL };
    346 	static const const conv_ds_t	*ds_cf[] = {
    347 		CONV_DS_ADDR(ds_shn_cf), NULL };
    348 	static const const conv_ds_t	*ds_cfnp[] = {
    349 		CONV_DS_ADDR(ds_shn_cfnp), NULL };
    350 	static const 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 
    370 const char *
    371 conv_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 
    378 conv_iter_ret_t
    379 conv_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