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