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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * String conversion routines for ELF header attributes. 30 */ 31 #include <stdio.h> 32 #include <string.h> 33 #include "_conv.h" 34 #include "elf_msg.h" 35 #include <sys/elf_SPARC.h> 36 37 38 39 /* Instantiate a local copy of conv_map2str() from _conv.h */ 40 DEFINE_conv_map2str 41 42 43 44 const char * 45 conv_ehdr_class(uchar_t class, Conv_fmt_flags_t fmt_flags, 46 Conv_inv_buf_t *inv_buf) 47 { 48 static const Msg classes[] = { 49 MSG_ELFCLASSNONE, MSG_ELFCLASS32, MSG_ELFCLASS64 50 }; 51 static const Msg classes_alt[] = { 52 MSG_ELFCLASSNONE_ALT, MSG_ELFCLASS32_ALT, MSG_ELFCLASS64_ALT 53 }; 54 55 /* Use alternative strings? */ 56 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 57 case CONV_FMT_ALT_DUMP: 58 case CONV_FMT_ALT_FILE: 59 return (conv_map2str(inv_buf, class, fmt_flags, 60 ARRAY_NELTS(classes_alt), classes_alt)); 61 } 62 63 /* Use default strings */ 64 return (conv_map2str(inv_buf, class, fmt_flags, 65 ARRAY_NELTS(classes), classes)); 66 } 67 68 const char * 69 conv_ehdr_data(uchar_t data, Conv_fmt_flags_t fmt_flags, 70 Conv_inv_buf_t *inv_buf) 71 { 72 static const Msg datas[] = { 73 MSG_ELFDATANONE, MSG_ELFDATA2LSB, MSG_ELFDATA2MSB 74 }; 75 static const Msg datas_dump[] = { 76 MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT1, MSG_ELFDATA2MSB_ALT1 77 }; 78 static const Msg datas_file[] = { 79 MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT2, MSG_ELFDATA2MSB_ALT2 80 }; 81 82 /* Use alternative strings? */ 83 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 84 case CONV_FMT_ALT_DUMP: 85 return (conv_map2str(inv_buf, data, fmt_flags, 86 ARRAY_NELTS(datas_dump), datas_dump)); 87 case CONV_FMT_ALT_FILE: 88 return (conv_map2str(inv_buf, data, fmt_flags, 89 ARRAY_NELTS(datas_file), datas_file)); 90 } 91 92 /* Use default strings */ 93 return (conv_map2str(inv_buf, data, fmt_flags, 94 ARRAY_NELTS(datas), datas)); 95 } 96 97 static const Msg machines[EM_NUM] = { 98 MSG_EM_NONE, MSG_EM_M32, MSG_EM_SPARC, 99 MSG_EM_386, MSG_EM_68K, MSG_EM_88K, 100 MSG_EM_486, MSG_EM_860, MSG_EM_MIPS, 101 MSG_EM_S370, MSG_EM_MIPS_RS3_LE, MSG_EM_RS6000, 102 MSG_EM_UNKNOWN12, MSG_EM_UNKNOWN13, MSG_EM_UNKNOWN14, 103 MSG_EM_PA_RISC, MSG_EM_nCUBE, MSG_EM_VPP500, 104 MSG_EM_SPARC32PLUS, MSG_EM_960, MSG_EM_PPC, 105 MSG_EM_PPC64, MSG_EM_S390, MSG_EM_UNKNOWN23, 106 MSG_EM_UNKNOWN24, MSG_EM_UNKNOWN25, MSG_EM_UNKNOWN26, 107 MSG_EM_UNKNOWN27, MSG_EM_UNKNOWN28, MSG_EM_UNKNOWN29, 108 MSG_EM_UNKNOWN30, MSG_EM_UNKNOWN31, MSG_EM_UNKNOWN32, 109 MSG_EM_UNKNOWN33, MSG_EM_UNKNOWN34, MSG_EM_UNKNOWN35, 110 MSG_EM_V800, MSG_EM_FR20, MSG_EM_RH32, 111 MSG_EM_RCE, MSG_EM_ARM, MSG_EM_ALPHA, 112 MSG_EM_SH, MSG_EM_SPARCV9, MSG_EM_TRICORE, 113 MSG_EM_ARC, MSG_EM_H8_300, MSG_EM_H8_300H, 114 MSG_EM_H8S, MSG_EM_H8_500, MSG_EM_IA_64, 115 MSG_EM_MIPS_X, MSG_EM_COLDFIRE, MSG_EM_68HC12, 116 MSG_EM_MMA, MSG_EM_PCP, MSG_EM_NCPU, 117 MSG_EM_NDR1, MSG_EM_STARCORE, MSG_EM_ME16, 118 MSG_EM_ST100, MSG_EM_TINYJ, MSG_EM_AMD64, 119 MSG_EM_PDSP, MSG_EM_UNKNOWN64, MSG_EM_UNKNOWN65, 120 MSG_EM_FX66, MSG_EM_ST9PLUS, MSG_EM_ST7, 121 MSG_EM_68HC16, MSG_EM_68HC11, MSG_EM_68HC08, 122 MSG_EM_68HC05, MSG_EM_SVX, MSG_EM_ST19, 123 MSG_EM_VAX, MSG_EM_CRIS, MSG_EM_JAVELIN, 124 MSG_EM_FIREPATH, MSG_EM_ZSP, MSG_EM_MMIX, 125 MSG_EM_HUANY, MSG_EM_PRISM, MSG_EM_AVR, 126 MSG_EM_FR30, MSG_EM_D10V, MSG_EM_D30V, 127 MSG_EM_V850, MSG_EM_M32R, MSG_EM_MN10300, 128 MSG_EM_MN10200, MSG_EM_PJ, MSG_EM_OPENRISC, 129 MSG_EM_ARC_A5, MSG_EM_XTENSA 130 }; 131 static const Msg machines_alt[EM_NUM] = { 132 MSG_EM_NONE_ALT, MSG_EM_M32_ALT, MSG_EM_SPARC_ALT, 133 MSG_EM_386_ALT, MSG_EM_68K_ALT, MSG_EM_88K_ALT, 134 MSG_EM_486_ALT, MSG_EM_860_ALT, MSG_EM_MIPS_ALT, 135 MSG_EM_S370, MSG_EM_MIPS_RS3_LE_ALT, MSG_EM_RS6000_ALT, 136 MSG_EM_UNKNOWN12, MSG_EM_UNKNOWN13, MSG_EM_UNKNOWN14, 137 MSG_EM_PA_RISC_ALT, MSG_EM_nCUBE_ALT, MSG_EM_VPP500_ALT, 138 MSG_EM_SPARC32PLUS_ALT, MSG_EM_960, MSG_EM_PPC_ALT, 139 MSG_EM_PPC64_ALT, MSG_EM_S390, MSG_EM_UNKNOWN23, 140 MSG_EM_UNKNOWN24, MSG_EM_UNKNOWN25, MSG_EM_UNKNOWN26, 141 MSG_EM_UNKNOWN27, MSG_EM_UNKNOWN28, MSG_EM_UNKNOWN29, 142 MSG_EM_UNKNOWN30, MSG_EM_UNKNOWN31, MSG_EM_UNKNOWN32, 143 MSG_EM_UNKNOWN33, MSG_EM_UNKNOWN34, MSG_EM_UNKNOWN35, 144 MSG_EM_V800, MSG_EM_FR20, MSG_EM_RH32, 145 MSG_EM_RCE, MSG_EM_ARM_ALT, MSG_EM_ALPHA_ALT, 146 MSG_EM_SH, MSG_EM_SPARCV9_ALT, MSG_EM_TRICORE, 147 MSG_EM_ARC, MSG_EM_H8_300, MSG_EM_H8_300H, 148 MSG_EM_H8S, MSG_EM_H8_500, MSG_EM_IA_64_ALT, 149 MSG_EM_MIPS_X, MSG_EM_COLDFIRE, MSG_EM_68HC12, 150 MSG_EM_MMA, MSG_EM_PCP, MSG_EM_NCPU, 151 MSG_EM_NDR1, MSG_EM_STARCORE, MSG_EM_ME16, 152 MSG_EM_ST100, MSG_EM_TINYJ, MSG_EM_AMD64_ALT, 153 MSG_EM_PDSP, MSG_EM_UNKNOWN64, MSG_EM_UNKNOWN65, 154 MSG_EM_FX66, MSG_EM_ST9PLUS, MSG_EM_ST7, 155 MSG_EM_68HC16, MSG_EM_68HC11, MSG_EM_68HC08, 156 MSG_EM_68HC05, MSG_EM_SVX, MSG_EM_ST19, 157 MSG_EM_VAX_ALT, MSG_EM_CRIS, MSG_EM_JAVELIN, 158 MSG_EM_FIREPATH, MSG_EM_ZSP, MSG_EM_MMIX, 159 MSG_EM_HUANY, MSG_EM_PRISM, MSG_EM_AVR, 160 MSG_EM_FR30, MSG_EM_D10V, MSG_EM_D30V, 161 MSG_EM_V850, MSG_EM_M32R, MSG_EM_MN10300, 162 MSG_EM_MN10200, MSG_EM_PJ, MSG_EM_OPENRISC, 163 MSG_EM_ARC_A5, MSG_EM_XTENSA 164 }; 165 #if (EM_NUM != (EM_XTENSA + 1)) 166 #error "EM_NUM has grown" 167 #endif 168 169 const char * 170 conv_ehdr_mach(Half machine, Conv_fmt_flags_t fmt_flags, 171 Conv_inv_buf_t *inv_buf) 172 { 173 /* Use alternative strings? */ 174 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 175 case CONV_FMT_ALT_DUMP: 176 case CONV_FMT_ALT_FILE: 177 return (conv_map2str(inv_buf, machine, fmt_flags, 178 ARRAY_NELTS(machines_alt), machines_alt)); 179 } 180 181 /* Use default strings */ 182 return (conv_map2str(inv_buf, machine, fmt_flags, 183 ARRAY_NELTS(machines), machines)); 184 } 185 186 187 const char * 188 conv_ehdr_type(Half etype, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) 189 { 190 static const Msg etypes[] = { 191 MSG_ET_NONE, MSG_ET_REL, MSG_ET_EXEC, 192 MSG_ET_DYN, MSG_ET_CORE 193 }; 194 static const Msg etypes_alt[] = { 195 MSG_ET_NONE_ALT, MSG_ET_REL_ALT, MSG_ET_EXEC_ALT, 196 MSG_ET_DYN_ALT, MSG_ET_CORE_ALT 197 }; 198 199 if (etype == ET_SUNWPSEUDO) { 200 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 201 case CONV_FMT_ALT_DUMP: 202 case CONV_FMT_ALT_FILE: 203 return (MSG_ORIG(MSG_ET_SUNWPSEUDO_ALT)); 204 default: 205 return (MSG_ORIG(MSG_ET_SUNWPSEUDO)); 206 } 207 } 208 209 /* Use alternative strings? */ 210 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 211 case CONV_FMT_ALT_DUMP: 212 case CONV_FMT_ALT_FILE: 213 return (conv_map2str(inv_buf, etype, fmt_flags, 214 ARRAY_NELTS(etypes_alt), etypes_alt)); 215 } 216 217 /* Use default strings */ 218 return (conv_map2str(inv_buf, etype, fmt_flags, 219 ARRAY_NELTS(etypes), etypes)); 220 221 } 222 223 const char * 224 conv_ehdr_vers(Word version, Conv_fmt_flags_t fmt_flags, 225 Conv_inv_buf_t *inv_buf) 226 { 227 static const Msg versions[] = { 228 MSG_EV_NONE, MSG_EV_CURRENT 229 }; 230 static const Msg versions_alt[] = { 231 MSG_EV_NONE_ALT, MSG_EV_CURRENT_ALT 232 }; 233 234 /* Use alternative strings? */ 235 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 236 case CONV_FMT_ALT_DUMP: 237 case CONV_FMT_ALT_FILE: 238 return (conv_map2str(inv_buf, version, fmt_flags, 239 ARRAY_NELTS(versions_alt), versions_alt)); 240 } 241 242 /* Use default strings */ 243 return (conv_map2str(inv_buf, version, fmt_flags, 244 ARRAY_NELTS(versions), versions)); 245 } 246 247 #define EFLAGSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \ 248 MSG_EF_SPARCV9_TSO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ 249 MSG_EF_SPARC_SUN_US1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ 250 MSG_EF_SPARC_HAL_R1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ 251 MSG_EF_SPARC_SUN_US3_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ 252 CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE 253 254 /* 255 * Ensure that Conv_ehdr_flags_buf_t is large enough: 256 * 257 * EFLAGSZ is the real minimum size of the buffer required by conv_ehdr_flags(). 258 * However, Conv_ehdr_flags_buf_t uses CONV_EHDR_FLAG_BUFSIZE to set the 259 * buffer size. We do things this way because the definition of EFLAGSZ uses 260 * information that is not available in the environment of other programs 261 * that include the conv.h header file. 262 */ 263 #if CONV_EHDR_FLAGS_BUFSIZE < EFLAGSZ 264 #error "CONV_EHDR_FLAGS_BUFSIZE is not large enough" 265 #endif 266 267 /* 268 * Make a string representation of the e_flags field. 269 */ 270 const char * 271 conv_ehdr_flags(Half mach, Word flags, Conv_fmt_flags_t fmt_flags, 272 Conv_ehdr_flags_buf_t *flags_buf) 273 { 274 static Val_desc vda[] = { 275 { EF_SPARC_32PLUS, MSG_ORIG(MSG_EF_SPARC_32PLUS) }, 276 { EF_SPARC_SUN_US1, MSG_ORIG(MSG_EF_SPARC_SUN_US1) }, 277 { EF_SPARC_HAL_R1, MSG_ORIG(MSG_EF_SPARC_HAL_R1) }, 278 { EF_SPARC_SUN_US3, MSG_ORIG(MSG_EF_SPARC_SUN_US3) }, 279 { 0, 0 } 280 }; 281 static const Msg mm_flags[] = { 282 MSG_EF_SPARCV9_TSO, MSG_EF_SPARCV9_PSO, 283 MSG_EF_SPARCV9_RMO 284 }; 285 static const char *leading_str_arr[2]; 286 static CONV_EXPN_FIELD_ARG conv_arg = { 287 NULL, sizeof (flags_buf->buf), vda, leading_str_arr }; 288 289 const char **lstr = leading_str_arr; 290 291 conv_arg.buf = flags_buf->buf; 292 293 /* 294 * Non-SPARC architectures presently provide no known flags. 295 */ 296 if ((mach == EM_SPARCV9) || (((mach == EM_SPARC) || 297 (mach == EM_SPARC32PLUS)) && flags)) { 298 /* 299 * Valid vendor extension bits for SPARCV9. These must be 300 * updated along with elf_SPARC.h. 301 */ 302 303 conv_arg.oflags = conv_arg.rflags = flags; 304 if ((mach == EM_SPARCV9) && (flags <= EF_SPARCV9_RMO)) { 305 *lstr++ = MSG_ORIG(mm_flags[flags & EF_SPARCV9_MM]); 306 conv_arg.rflags &= ~EF_SPARCV9_MM; 307 } 308 *lstr = NULL; 309 310 (void) conv_expn_field(&conv_arg, fmt_flags); 311 312 return (conv_arg.buf); 313 } 314 315 return (conv_invalid_val(&flags_buf->inv_buf, flags, CONV_FMT_DECIMAL)); 316 } 317 318 /* 319 * Make a string representation of the e_ident[EI_OSABI] field. 320 */ 321 const char * 322 conv_ehdr_osabi(uchar_t osabi, Conv_fmt_flags_t fmt_flags, 323 Conv_inv_buf_t *inv_buf) 324 { 325 static const Msg osabi_arr[] = { 326 MSG_OSABI_NONE, MSG_OSABI_HPUX, 327 MSG_OSABI_NETBSD, MSG_OSABI_LINUX, 328 MSG_OSABI_UNKNOWN4, MSG_OSABI_UNKNOWN5, 329 MSG_OSABI_SOLARIS, MSG_OSABI_AIX, 330 MSG_OSABI_IRIX, MSG_OSABI_FREEBSD, 331 MSG_OSABI_TRU64, MSG_OSABI_MODESTO, 332 MSG_OSABI_OPENBSD, MSG_OSABI_OPENVMS, 333 MSG_OSABI_NSK, MSG_OSABI_AROS 334 }; 335 static const Msg osabi_arr_alt[] = { 336 MSG_OSABI_NONE_ALT, MSG_OSABI_HPUX_ALT, 337 MSG_OSABI_NETBSD_ALT, MSG_OSABI_LINUX_ALT, 338 MSG_OSABI_UNKNOWN4, MSG_OSABI_UNKNOWN5, 339 MSG_OSABI_SOLARIS_ALT, MSG_OSABI_AIX_ALT, 340 MSG_OSABI_IRIX_ALT, MSG_OSABI_FREEBSD_ALT, 341 MSG_OSABI_TRU64_ALT, MSG_OSABI_MODESTO_ALT, 342 MSG_OSABI_OPENBSD_ALT, MSG_OSABI_OPENVMS_ALT, 343 MSG_OSABI_NSK_ALT, MSG_OSABI_AROS_ALT 344 }; 345 346 const char *str; 347 348 switch (osabi) { 349 case ELFOSABI_ARM: 350 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 351 case CONV_FMT_ALT_DUMP: 352 case CONV_FMT_ALT_FILE: 353 str = MSG_ORIG(MSG_OSABI_ARM_ALT); 354 break; 355 default: 356 str = MSG_ORIG(MSG_OSABI_ARM); 357 } 358 break; 359 360 case ELFOSABI_STANDALONE: 361 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 362 case CONV_FMT_ALT_DUMP: 363 case CONV_FMT_ALT_FILE: 364 str = MSG_ORIG(MSG_OSABI_STANDALONE_ALT); 365 break; 366 default: 367 str = MSG_ORIG(MSG_OSABI_STANDALONE); 368 } 369 break; 370 371 default: 372 switch (CONV_TYPE_FMT_ALT(fmt_flags)) { 373 case CONV_FMT_ALT_DUMP: 374 case CONV_FMT_ALT_FILE: 375 str = conv_map2str(inv_buf, osabi, fmt_flags, 376 ARRAY_NELTS(osabi_arr_alt), osabi_arr_alt); 377 break; 378 default: 379 str = conv_map2str(inv_buf, osabi, fmt_flags, 380 ARRAY_NELTS(osabi_arr), osabi_arr); 381 } 382 break; 383 } 384 385 return (str); 386 } 387 388 /* 389 * A generic means of returning additional information for a rejected file in 390 * terms of a string. 391 */ 392 const char * 393 conv_reject_desc(Rej_desc * rej, Conv_reject_desc_buf_t *reject_desc_buf) 394 { 395 ushort_t type = rej->rej_type; 396 uint_t info = rej->rej_info; 397 398 if (type == SGS_REJ_MACH) 399 /* LINTED */ 400 return (conv_ehdr_mach((Half)info, 0, 401 &reject_desc_buf->inv_buf)); 402 else if (type == SGS_REJ_CLASS) 403 /* LINTED */ 404 return (conv_ehdr_class((uchar_t)info, 0, 405 &reject_desc_buf->inv_buf)); 406 else if (type == SGS_REJ_DATA) 407 /* LINTED */ 408 return (conv_ehdr_data((uchar_t)info, 0, 409 &reject_desc_buf->inv_buf)); 410 else if (type == SGS_REJ_TYPE) 411 /* LINTED */ 412 return (conv_ehdr_type((Half)info, 0, 413 &reject_desc_buf->inv_buf)); 414 else if ((type == SGS_REJ_BADFLAG) || (type == SGS_REJ_MISFLAG) || 415 (type == SGS_REJ_HAL) || (type == SGS_REJ_US3)) 416 /* 417 * Only called from ld.so.1, thus M_MACH is hardcoded. 418 */ 419 return (conv_ehdr_flags(M_MACH, (Word)info, 0, 420 &reject_desc_buf->flags_buf)); 421 else if (type == SGS_REJ_UNKFILE) 422 return ((const char *)0); 423 else if ((type == SGS_REJ_STR) || (type == SGS_REJ_HWCAP_1)) { 424 if (rej->rej_str) 425 return ((const char *)rej->rej_str); 426 else 427 return (MSG_ORIG(MSG_STR_EMPTY)); 428 } else 429 return (conv_invalid_val(&reject_desc_buf->inv_buf, info, 430 CONV_FMT_DECIMAL)); 431 } 432