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